@teambit/doctor 0.0.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.
- package/core-diagnoses/broken-symlink-files.ts +78 -0
- package/core-diagnoses/orphan-symlink-objects.ts +51 -0
- package/core-diagnoses/validate-bit-version.ts +56 -0
- package/core-diagnoses/validate-git-exec.ts +38 -0
- package/core-diagnoses/validate-npm-exec.ts +40 -0
- package/core-diagnoses/validate-workspace-bit-json-syntax.ts +35 -0
- package/core-diagnoses/validate-yarn-exec.ts +40 -0
- package/diagnosis-list-template.ts +28 -0
- package/diagnosis.ts +81 -0
- package/dist/core-diagnoses/broken-symlink-files.d.ts +15 -0
- package/dist/core-diagnoses/broken-symlink-files.js +127 -0
- package/dist/core-diagnoses/broken-symlink-files.js.map +1 -0
- package/dist/core-diagnoses/orphan-symlink-objects.d.ts +10 -0
- package/dist/core-diagnoses/orphan-symlink-objects.js +84 -0
- package/dist/core-diagnoses/orphan-symlink-objects.js.map +1 -0
- package/dist/core-diagnoses/validate-bit-version.d.ts +9 -0
- package/dist/core-diagnoses/validate-bit-version.js +94 -0
- package/dist/core-diagnoses/validate-bit-version.js.map +1 -0
- package/dist/core-diagnoses/validate-git-exec.d.ts +10 -0
- package/dist/core-diagnoses/validate-git-exec.js +69 -0
- package/dist/core-diagnoses/validate-git-exec.js.map +1 -0
- package/dist/core-diagnoses/validate-npm-exec.d.ts +10 -0
- package/dist/core-diagnoses/validate-npm-exec.js +73 -0
- package/dist/core-diagnoses/validate-npm-exec.js.map +1 -0
- package/dist/core-diagnoses/validate-workspace-bit-json-syntax.d.ts +9 -0
- package/dist/core-diagnoses/validate-workspace-bit-json-syntax.js +67 -0
- package/dist/core-diagnoses/validate-workspace-bit-json-syntax.js.map +1 -0
- package/dist/core-diagnoses/validate-yarn-exec.d.ts +10 -0
- package/dist/core-diagnoses/validate-yarn-exec.js +72 -0
- package/dist/core-diagnoses/validate-yarn-exec.js.map +1 -0
- package/dist/diagnosis-list-template.d.ts +2 -0
- package/dist/diagnosis-list-template.js +42 -0
- package/dist/diagnosis-list-template.js.map +1 -0
- package/dist/diagnosis.d.ts +41 -0
- package/dist/diagnosis.js +74 -0
- package/dist/diagnosis.js.map +1 -0
- package/dist/doctor-cmd.d.ts +21 -0
- package/dist/doctor-cmd.js +125 -0
- package/dist/doctor-cmd.js.map +1 -0
- package/dist/doctor-registrar-builder.d.ts +2 -0
- package/dist/doctor-registrar-builder.js +69 -0
- package/dist/doctor-registrar-builder.js.map +1 -0
- package/dist/doctor-registrar.d.ts +21 -0
- package/dist/doctor-registrar.js +63 -0
- package/dist/doctor-registrar.js.map +1 -0
- package/dist/doctor-results-template.d.ts +2 -0
- package/dist/doctor-results-template.js +115 -0
- package/dist/doctor-results-template.js.map +1 -0
- package/dist/doctor.aspect.d.ts +2 -0
- package/dist/doctor.aspect.js +18 -0
- package/dist/doctor.aspect.js.map +1 -0
- package/dist/doctor.d.ts +31 -0
- package/dist/doctor.js +342 -0
- package/dist/doctor.js.map +1 -0
- package/dist/doctor.main.runtime.d.ts +8 -0
- package/dist/doctor.main.runtime.js +44 -0
- package/dist/doctor.main.runtime.js.map +1 -0
- package/dist/esm.mjs +6 -0
- package/dist/exceptions/diagnosis-not-found.d.ts +5 -0
- package/dist/exceptions/diagnosis-not-found.js +30 -0
- package/dist/exceptions/diagnosis-not-found.js.map +1 -0
- package/dist/exceptions/missing-diagnosis-name.d.ts +4 -0
- package/dist/exceptions/missing-diagnosis-name.js +21 -0
- package/dist/exceptions/missing-diagnosis-name.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/preview-1719544843434.js +7 -0
- package/doctor-cmd.ts +97 -0
- package/doctor-registrar-builder.ts +22 -0
- package/doctor-registrar.ts +58 -0
- package/doctor-results-template.ts +105 -0
- package/doctor.aspect.ts +5 -0
- package/doctor.main.runtime.ts +17 -0
- package/doctor.ts +250 -0
- package/esm.mjs +6 -0
- package/exceptions/diagnosis-not-found.ts +8 -0
- package/exceptions/missing-diagnosis-name.ts +7 -0
- package/index.ts +7 -0
- package/package.json +54 -0
- package/tsconfig.json +45 -0
- package/types/asset.d.ts +29 -0
- package/types/style.d.ts +42 -0
package/doctor-cmd.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import runAll, { DoctorOptions, listDiagnoses, runOne } from './doctor';
|
|
2
|
+
import { Command, CommandOptions } from '@teambit/cli';
|
|
3
|
+
import formatDiagnosesList from './diagnosis-list-template';
|
|
4
|
+
import formatDiagnosesResult from './doctor-results-template';
|
|
5
|
+
|
|
6
|
+
type Flags = {
|
|
7
|
+
list?: boolean;
|
|
8
|
+
save?: string;
|
|
9
|
+
archive?: string;
|
|
10
|
+
includeNodeModules?: boolean;
|
|
11
|
+
includePublic?: boolean;
|
|
12
|
+
excludeLocalScope?: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export class DoctorCmd implements Command {
|
|
16
|
+
name = 'doctor [diagnosis-name]';
|
|
17
|
+
description = 'diagnose a bit workspace';
|
|
18
|
+
group = 'general';
|
|
19
|
+
alias = '';
|
|
20
|
+
loadAspects = false;
|
|
21
|
+
options = [
|
|
22
|
+
['j', 'json', 'return diagnoses in json format'],
|
|
23
|
+
['', 'list', 'list all available diagnoses'],
|
|
24
|
+
['s', 'save [filePath]', 'save diagnoses to a file'],
|
|
25
|
+
[
|
|
26
|
+
'a',
|
|
27
|
+
'archive [filePath]',
|
|
28
|
+
'archive the workspace including diagnosis info (by default exclude node-modules and include .bit)',
|
|
29
|
+
],
|
|
30
|
+
['n', 'include-node-modules', 'relevant for --archive. include node_modules in the archive file'],
|
|
31
|
+
['p', 'include-public', 'relevant for --archive. include public folder in the archive file'],
|
|
32
|
+
['e', 'exclude-local-scope', 'relevant for --archive. exclude .bit or .git/bit from the archive file'],
|
|
33
|
+
] as CommandOptions;
|
|
34
|
+
|
|
35
|
+
async report([diagnosisName]: string[], flags: Flags) {
|
|
36
|
+
const res = await this.runDiag(diagnosisName, flags);
|
|
37
|
+
if (flags.list) {
|
|
38
|
+
return formatDiagnosesList(res);
|
|
39
|
+
}
|
|
40
|
+
if (diagnosisName) {
|
|
41
|
+
const { examineResult, savedFilePath, metaData } = res;
|
|
42
|
+
return formatDiagnosesResult({ examineResults: [examineResult], savedFilePath, metaData });
|
|
43
|
+
}
|
|
44
|
+
const { examineResults, savedFilePath, metaData } = res;
|
|
45
|
+
return formatDiagnosesResult({ examineResults, savedFilePath, metaData });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async json([diagnosisName]: string[], flags: Flags) {
|
|
49
|
+
const res = await this.runDiag(diagnosisName, flags);
|
|
50
|
+
if (flags.list) {
|
|
51
|
+
return res;
|
|
52
|
+
}
|
|
53
|
+
const { examineResults, examineResult, savedFilePath } = res;
|
|
54
|
+
const fullJson = {
|
|
55
|
+
savedFilePath,
|
|
56
|
+
examineResult,
|
|
57
|
+
examineResults,
|
|
58
|
+
};
|
|
59
|
+
return fullJson;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private async runDiag(diagnosisName?: string, flags: Flags = {}): Promise<any> {
|
|
63
|
+
const {
|
|
64
|
+
list = false,
|
|
65
|
+
save,
|
|
66
|
+
archive,
|
|
67
|
+
includeNodeModules = false,
|
|
68
|
+
includePublic = false,
|
|
69
|
+
excludeLocalScope = false,
|
|
70
|
+
} = flags;
|
|
71
|
+
|
|
72
|
+
if (list) {
|
|
73
|
+
return listDiagnoses();
|
|
74
|
+
}
|
|
75
|
+
if ((includeNodeModules || excludeLocalScope) && !archive) {
|
|
76
|
+
throw new Error('to use --include-node-modules or --exclude-local-scope please specify --archive');
|
|
77
|
+
}
|
|
78
|
+
let filePath = save;
|
|
79
|
+
// Happen when used --save without specify the location
|
|
80
|
+
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
|
|
81
|
+
if (save === true || archive === true) {
|
|
82
|
+
filePath = '.';
|
|
83
|
+
}
|
|
84
|
+
if (typeof archive === 'string') {
|
|
85
|
+
filePath = archive;
|
|
86
|
+
}
|
|
87
|
+
const doctorOptions: DoctorOptions = {
|
|
88
|
+
diagnosisName,
|
|
89
|
+
filePath,
|
|
90
|
+
archiveWorkspace: Boolean(archive),
|
|
91
|
+
includeNodeModules,
|
|
92
|
+
includePublic,
|
|
93
|
+
excludeLocalScope,
|
|
94
|
+
};
|
|
95
|
+
return diagnosisName ? runOne(doctorOptions) : runAll(doctorOptions);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import BrokenSymlinkFiles from './core-diagnoses/broken-symlink-files';
|
|
2
|
+
import OrphanSymlinkObjects from './core-diagnoses/orphan-symlink-objects';
|
|
3
|
+
import ValidateBitVersion from './core-diagnoses/validate-bit-version';
|
|
4
|
+
import ValidateGitExec from './core-diagnoses/validate-git-exec';
|
|
5
|
+
import ValidateNpmExec from './core-diagnoses/validate-npm-exec';
|
|
6
|
+
import ValidateWorkspaceBitJsonSyntax from './core-diagnoses/validate-workspace-bit-json-syntax';
|
|
7
|
+
import ValidateYarnExec from './core-diagnoses/validate-yarn-exec';
|
|
8
|
+
import Diagnosis from './diagnosis';
|
|
9
|
+
import DoctorRegistrar from './doctor-registrar';
|
|
10
|
+
|
|
11
|
+
export default function registerCoreAndExtensionsDiagnoses(extensionDiagnoses: Diagnosis[] = []) {
|
|
12
|
+
const diagnoses = [
|
|
13
|
+
new ValidateWorkspaceBitJsonSyntax(),
|
|
14
|
+
new ValidateGitExec(),
|
|
15
|
+
new OrphanSymlinkObjects(),
|
|
16
|
+
new BrokenSymlinkFiles(),
|
|
17
|
+
new ValidateNpmExec(),
|
|
18
|
+
new ValidateYarnExec(),
|
|
19
|
+
new ValidateBitVersion(),
|
|
20
|
+
].concat(extensionDiagnoses);
|
|
21
|
+
DoctorRegistrar.init(diagnoses);
|
|
22
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import Diagnosis from './diagnosis';
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Setting up block level variable to store class state
|
|
5
|
+
* set's to null by default.
|
|
6
|
+
*/
|
|
7
|
+
let instance: DoctorRegistrar | null = null;
|
|
8
|
+
|
|
9
|
+
const _checkName = (name) => (diagnosis: Diagnosis) => {
|
|
10
|
+
return diagnosis.name === name;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default class DoctorRegistrar {
|
|
14
|
+
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
|
|
15
|
+
diagnoses: Diagnosis[];
|
|
16
|
+
|
|
17
|
+
constructor() {
|
|
18
|
+
if (!instance) {
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
20
|
+
instance = this;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return instance;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Initialize the default diagnoses
|
|
28
|
+
*/
|
|
29
|
+
static init(diagnoses: Diagnosis[] = []) {
|
|
30
|
+
const self = new DoctorRegistrar();
|
|
31
|
+
self.diagnoses = diagnoses;
|
|
32
|
+
// diagnoses.forEach(diagnosis => self.diagnoses.push(diagnosis));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get the instance of the DoctorRegistrar
|
|
37
|
+
* @return {DoctorRegistrar} instance of the DoctorRegistrar
|
|
38
|
+
*
|
|
39
|
+
*/
|
|
40
|
+
static getInstance(): DoctorRegistrar {
|
|
41
|
+
if (!instance) {
|
|
42
|
+
DoctorRegistrar.init();
|
|
43
|
+
}
|
|
44
|
+
return instance as DoctorRegistrar;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Register a new diagnosis
|
|
49
|
+
* @param {Diagnosis} diagnosis
|
|
50
|
+
*/
|
|
51
|
+
registerDiagnosis(diagnosis: Diagnosis) {
|
|
52
|
+
this.diagnoses.push(diagnosis);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getDiagnosisByName(name: string) {
|
|
56
|
+
return this.diagnoses.find(_checkName(name));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { table } from 'table';
|
|
3
|
+
import { DoctorMetaData, DoctorRunAllResults } from './doctor';
|
|
4
|
+
import { ExamineResult } from './diagnosis';
|
|
5
|
+
|
|
6
|
+
// const NAME_COLUMN_WIDTH = 100;
|
|
7
|
+
// const DESCRIPTION_COLUMN_WIDTH = 30;
|
|
8
|
+
|
|
9
|
+
const summeryTableColumnConfig = {
|
|
10
|
+
columnDefault: {
|
|
11
|
+
alignment: 'left',
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type SummeryRow = [string, string, string, string];
|
|
16
|
+
|
|
17
|
+
function _formatStatusCell(status: boolean): string {
|
|
18
|
+
if (status) {
|
|
19
|
+
return chalk.green('passed');
|
|
20
|
+
}
|
|
21
|
+
return chalk.red('failed');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function _createSummeryRow(examineResult: ExamineResult): SummeryRow {
|
|
25
|
+
const meta = examineResult.diagnosisMetaData;
|
|
26
|
+
const status = _formatStatusCell(examineResult.bareResult.valid);
|
|
27
|
+
return [meta.category, meta.name, meta.description, status];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function _createSummeryTable(examineResult: ExamineResult[]): string {
|
|
31
|
+
const header = [chalk.bold('category'), chalk.bold('name'), chalk.bold('description'), chalk.bold('status')];
|
|
32
|
+
const rows = examineResult.map(_createSummeryRow);
|
|
33
|
+
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
|
|
34
|
+
rows.unshift(header);
|
|
35
|
+
const output = table(rows, summeryTableColumnConfig);
|
|
36
|
+
return output;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function _createSummerySection(examineResult: ExamineResult[]): string {
|
|
40
|
+
// A placeholder if we will decide we want a title
|
|
41
|
+
const title = chalk.underline('');
|
|
42
|
+
const summeryTable = _createSummeryTable(examineResult);
|
|
43
|
+
return `${title}\n${summeryTable}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function _createFullReportForDiagnosis(examineResult: ExamineResult): string {
|
|
47
|
+
if (examineResult.bareResult.valid) {
|
|
48
|
+
return '';
|
|
49
|
+
}
|
|
50
|
+
const title = chalk.underline(examineResult.diagnosisMetaData.name);
|
|
51
|
+
const symptomsTitle = chalk.underline('symptoms');
|
|
52
|
+
const symptomsText = examineResult.formattedSymptoms;
|
|
53
|
+
const cureTitle = chalk.underline('cure');
|
|
54
|
+
const cureText = examineResult.formattedManualTreat;
|
|
55
|
+
return `${title}
|
|
56
|
+
${symptomsTitle}
|
|
57
|
+
${symptomsText}
|
|
58
|
+
${cureTitle}
|
|
59
|
+
${cureText}\n`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function _createFullReportForDiagnoses(examineResult: ExamineResult[]): string {
|
|
63
|
+
const fullDiagnosesReport = examineResult.map(_createFullReportForDiagnosis).join('\n');
|
|
64
|
+
return fullDiagnosesReport;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function _createFullReportSection(examineResult: ExamineResult[]): string {
|
|
68
|
+
const title = chalk.underline('Error report');
|
|
69
|
+
const fullDiagnosesReport = _createFullReportForDiagnoses(examineResult);
|
|
70
|
+
if (fullDiagnosesReport.trim() === '') {
|
|
71
|
+
return '';
|
|
72
|
+
}
|
|
73
|
+
return `${title}
|
|
74
|
+
${fullDiagnosesReport}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function _createWrittenFileSection(savedFilePath) {
|
|
78
|
+
if (!savedFilePath) {
|
|
79
|
+
return '';
|
|
80
|
+
}
|
|
81
|
+
return `File written to ${savedFilePath}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function _createMetaSection(metaData: DoctorMetaData) {
|
|
85
|
+
return `
|
|
86
|
+
bit version : ${metaData.bitVersion}
|
|
87
|
+
node version : ${metaData.nodeVersion}
|
|
88
|
+
npm version : ${metaData.npmVersion || 'NA'}
|
|
89
|
+
yarn version : ${metaData.yarnVersion || 'NA'}
|
|
90
|
+
platform : ${metaData.platform}
|
|
91
|
+
user details : ${metaData.userDetails}
|
|
92
|
+
`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export default function render({ examineResults, savedFilePath, metaData }: DoctorRunAllResults): string {
|
|
96
|
+
const meatSection = _createMetaSection(metaData);
|
|
97
|
+
const summerySection = _createSummerySection(examineResults);
|
|
98
|
+
const fullReportSection = _createFullReportSection(examineResults);
|
|
99
|
+
const writtenFileSection = _createWrittenFileSection(savedFilePath);
|
|
100
|
+
const output = `${meatSection}
|
|
101
|
+
${summerySection}
|
|
102
|
+
${fullReportSection}
|
|
103
|
+
${writtenFileSection}`;
|
|
104
|
+
return output;
|
|
105
|
+
}
|
package/doctor.aspect.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CLIAspect, CLIMain, MainRuntime } from '@teambit/cli';
|
|
2
|
+
import { DoctorAspect } from './doctor.aspect';
|
|
3
|
+
import { DoctorCmd } from './doctor-cmd';
|
|
4
|
+
|
|
5
|
+
export class DoctorMain {
|
|
6
|
+
static slots = [];
|
|
7
|
+
static dependencies = [CLIAspect];
|
|
8
|
+
static runtime = MainRuntime;
|
|
9
|
+
static async provider([cliMain]: [CLIMain]) {
|
|
10
|
+
cliMain.register(new DoctorCmd());
|
|
11
|
+
return new DoctorMain();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
DoctorAspect.addRuntime(DoctorMain);
|
|
16
|
+
|
|
17
|
+
export default DoctorMain;
|
package/doctor.ts
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
|
|
4
|
+
import Stream from 'stream';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import tar from 'tar-stream';
|
|
7
|
+
import tarFS from 'tar-fs';
|
|
8
|
+
import { getHarmonyVersion } from '@teambit/legacy/dist/bootstrap';
|
|
9
|
+
import { CFG_USER_EMAIL_KEY, CFG_USER_NAME_KEY, DEBUG_LOG } from '@teambit/legacy/dist/constants';
|
|
10
|
+
import BitMap from '@teambit/legacy/dist/consumer/bit-map';
|
|
11
|
+
import WorkspaceConfig from '@teambit/legacy/dist/consumer/config/workspace-config';
|
|
12
|
+
import { ConsumerInfo, getConsumerInfo } from '@teambit/legacy/dist/consumer/consumer-locator';
|
|
13
|
+
import Diagnosis, { ExamineResult } from './diagnosis';
|
|
14
|
+
import DoctorRegistrar from './doctor-registrar';
|
|
15
|
+
import registerCoreAndExtensionsDiagnoses from './doctor-registrar-builder';
|
|
16
|
+
import logger from '@teambit/legacy/dist/logger/logger';
|
|
17
|
+
import { getExt, getWithoutExt, removeChalkCharacters } from '@teambit/legacy/dist/utils';
|
|
18
|
+
import { findScopePath } from '@teambit/scope.modules.find-scope-path';
|
|
19
|
+
import * as globalConfig from '@teambit/legacy/dist/api/consumer/lib/global-config';
|
|
20
|
+
import { getNpmVersion } from './core-diagnoses/validate-npm-exec';
|
|
21
|
+
import { getYarnVersion } from './core-diagnoses/validate-yarn-exec';
|
|
22
|
+
import { DiagnosisNotFound } from './exceptions/diagnosis-not-found';
|
|
23
|
+
import { MissingDiagnosisName } from './exceptions/missing-diagnosis-name';
|
|
24
|
+
|
|
25
|
+
// run specific check
|
|
26
|
+
export type DoctorMetaData = {
|
|
27
|
+
nodeVersion: string;
|
|
28
|
+
runningTimestamp: number;
|
|
29
|
+
platform: string;
|
|
30
|
+
bitVersion: string;
|
|
31
|
+
npmVersion: string;
|
|
32
|
+
yarnVersion: string;
|
|
33
|
+
userDetails: string;
|
|
34
|
+
};
|
|
35
|
+
export type DoctorRunAllResults = {
|
|
36
|
+
examineResults: ExamineResult[];
|
|
37
|
+
savedFilePath: string | null | undefined;
|
|
38
|
+
metaData: DoctorMetaData;
|
|
39
|
+
};
|
|
40
|
+
export type DoctorRunOneResult = {
|
|
41
|
+
examineResult: ExamineResult;
|
|
42
|
+
savedFilePath: string | null | undefined;
|
|
43
|
+
metaData: DoctorMetaData;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
let runningTimeStamp;
|
|
47
|
+
|
|
48
|
+
export type DoctorOptions = {
|
|
49
|
+
diagnosisName?: string;
|
|
50
|
+
filePath?: string;
|
|
51
|
+
archiveWorkspace?: boolean;
|
|
52
|
+
includeNodeModules?: boolean;
|
|
53
|
+
includePublic?: boolean;
|
|
54
|
+
excludeLocalScope?: boolean;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export default async function runAll(options: DoctorOptions): Promise<DoctorRunAllResults> {
|
|
58
|
+
registerCoreAndExtensionsDiagnoses();
|
|
59
|
+
runningTimeStamp = _getTimeStamp();
|
|
60
|
+
const doctorRegistrar = DoctorRegistrar.getInstance();
|
|
61
|
+
const examineP = doctorRegistrar.diagnoses.map((diagnosis) => diagnosis.examine());
|
|
62
|
+
const examineResults = await Promise.all(examineP);
|
|
63
|
+
const envMeta = await _getEnvMeta();
|
|
64
|
+
const savedFilePath = await _saveExamineResultsToFile(examineResults, envMeta, options);
|
|
65
|
+
return { examineResults, savedFilePath, metaData: envMeta };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function runOne({ diagnosisName, ...options }: DoctorOptions): Promise<DoctorRunOneResult> {
|
|
69
|
+
if (!diagnosisName) {
|
|
70
|
+
throw new MissingDiagnosisName();
|
|
71
|
+
}
|
|
72
|
+
registerCoreAndExtensionsDiagnoses();
|
|
73
|
+
runningTimeStamp = _getTimeStamp();
|
|
74
|
+
const doctorRegistrar = DoctorRegistrar.getInstance();
|
|
75
|
+
const diagnosis = doctorRegistrar.getDiagnosisByName(diagnosisName);
|
|
76
|
+
if (!diagnosis) {
|
|
77
|
+
throw new DiagnosisNotFound(diagnosisName);
|
|
78
|
+
}
|
|
79
|
+
const examineResult = await diagnosis.examine();
|
|
80
|
+
const envMeta = await _getEnvMeta();
|
|
81
|
+
const savedFilePath = await _saveExamineResultsToFile([examineResult], envMeta, options);
|
|
82
|
+
return { examineResult, savedFilePath, metaData: envMeta };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function listDiagnoses(): Promise<Diagnosis[]> {
|
|
86
|
+
registerCoreAndExtensionsDiagnoses();
|
|
87
|
+
const doctorRegistrar = DoctorRegistrar.getInstance();
|
|
88
|
+
return Promise.resolve(doctorRegistrar.diagnoses);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function _saveExamineResultsToFile(
|
|
92
|
+
examineResults: ExamineResult[],
|
|
93
|
+
envMeta: DoctorMetaData,
|
|
94
|
+
options: DoctorOptions
|
|
95
|
+
): Promise<string | null | undefined> {
|
|
96
|
+
if (!options.filePath) {
|
|
97
|
+
return Promise.resolve(undefined);
|
|
98
|
+
}
|
|
99
|
+
const finalFilePath = _calculateFinalFileName(options.filePath);
|
|
100
|
+
const packStream = await _generateExamineResultsTarFile(examineResults, envMeta, finalFilePath, options);
|
|
101
|
+
|
|
102
|
+
const yourTarball = fs.createWriteStream(finalFilePath);
|
|
103
|
+
|
|
104
|
+
packStream.pipe(yourTarball);
|
|
105
|
+
|
|
106
|
+
return new Promise((resolve) => {
|
|
107
|
+
yourTarball.on('close', function () {
|
|
108
|
+
logger.info(`wrote a file by bit doctor, file path: ${finalFilePath}`);
|
|
109
|
+
resolve(finalFilePath);
|
|
110
|
+
// fs.stat(finalFilePath, function (err, stats) {
|
|
111
|
+
// if (err) throw err
|
|
112
|
+
// console.log(stats)
|
|
113
|
+
// console.log('Got file info successfully!')
|
|
114
|
+
// })
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function _calculateFinalFileName(fileName: string): string {
|
|
120
|
+
if (fileName === '.') {
|
|
121
|
+
return _getDefaultFileName();
|
|
122
|
+
}
|
|
123
|
+
let finalFileName = fileName;
|
|
124
|
+
if (getExt(fileName) !== 'tar' && getExt(fileName) !== 'tar.gz') {
|
|
125
|
+
finalFileName = `${getWithoutExt(finalFileName)}.tar`;
|
|
126
|
+
}
|
|
127
|
+
return finalFileName;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function _getDefaultFileName() {
|
|
131
|
+
const timestamp = runningTimeStamp || _getTimeStamp();
|
|
132
|
+
return `doctor-results-${timestamp}.tar`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// TODO: move to utils
|
|
136
|
+
function _getTimeStamp() {
|
|
137
|
+
const d = new Date();
|
|
138
|
+
const timestamp = d.getTime();
|
|
139
|
+
return timestamp;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function _generateExamineResultsTarFile(
|
|
143
|
+
examineResults: ExamineResult[],
|
|
144
|
+
envMeta: DoctorMetaData,
|
|
145
|
+
tarFilePath: string,
|
|
146
|
+
options: DoctorOptions
|
|
147
|
+
): Promise<Stream.Readable> {
|
|
148
|
+
const { archiveWorkspace, includeNodeModules, includePublic, excludeLocalScope } = options;
|
|
149
|
+
const debugLog = await _getDebugLogAsBuffer();
|
|
150
|
+
const consumerInfo = await _getConsumerInfo();
|
|
151
|
+
let bitmap;
|
|
152
|
+
if (consumerInfo && consumerInfo.path) {
|
|
153
|
+
bitmap = _getBitMap(consumerInfo.path);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const packExamineResults = async (pack) => {
|
|
157
|
+
pack.entry({ name: 'env-meta.json' }, JSON.stringify(envMeta, null, 2));
|
|
158
|
+
pack.entry({ name: 'doc-results.json' }, JSON.stringify(examineResults, null, 2));
|
|
159
|
+
if (debugLog) {
|
|
160
|
+
pack.entry({ name: 'debug.log' }, debugLog);
|
|
161
|
+
}
|
|
162
|
+
if (!archiveWorkspace && bitmap) {
|
|
163
|
+
pack.entry({ name: '.bitmap' }, bitmap);
|
|
164
|
+
}
|
|
165
|
+
if (consumerInfo && consumerInfo.hasConsumerConfig) {
|
|
166
|
+
// TODO: support new config as well
|
|
167
|
+
const scopePath = findScopePath(consumerInfo.path);
|
|
168
|
+
const config = scopePath ? await WorkspaceConfig.loadIfExist(consumerInfo.path, scopePath) : undefined;
|
|
169
|
+
const legacyPlainConfig = config?._legacyPlainObject();
|
|
170
|
+
if (legacyPlainConfig) {
|
|
171
|
+
pack.entry({ name: 'config.json' }, JSON.stringify(legacyPlainConfig, null, 4));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
pack.finalize();
|
|
176
|
+
|
|
177
|
+
return pack;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
if (!archiveWorkspace) {
|
|
181
|
+
const pack = tar.pack(); // pack is a streams2 stream
|
|
182
|
+
return packExamineResults(pack);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const ignore = (fileName: string) => {
|
|
186
|
+
if (fileName === tarFilePath) return true;
|
|
187
|
+
if (fileName === '.DS_Store') return true;
|
|
188
|
+
if (
|
|
189
|
+
!includeNodeModules &&
|
|
190
|
+
(fileName.startsWith(`node_modules${path.sep}`) || fileName.includes(`${path.sep}node_modules${path.sep}`))
|
|
191
|
+
)
|
|
192
|
+
return true;
|
|
193
|
+
if (
|
|
194
|
+
!includePublic &&
|
|
195
|
+
(fileName.startsWith(`public${path.sep}`) || fileName.includes(`${path.sep}public${path.sep}`))
|
|
196
|
+
)
|
|
197
|
+
return true;
|
|
198
|
+
const isGit = fileName.startsWith(`.git${path.sep}`);
|
|
199
|
+
const isLocalScope = fileName.startsWith(`.bit${path.sep}`) || fileName.startsWith(`.git${path.sep}bit${path.sep}`);
|
|
200
|
+
if (excludeLocalScope && isLocalScope) return true;
|
|
201
|
+
if (isGit && !isLocalScope) return true;
|
|
202
|
+
return false;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const myPack = tarFS.pack('.', {
|
|
206
|
+
ignore,
|
|
207
|
+
finalize: false,
|
|
208
|
+
finish: packExamineResults,
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
return myPack;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function _getEnvMeta(): Promise<DoctorMetaData> {
|
|
215
|
+
const env = {
|
|
216
|
+
nodeVersion: process.version,
|
|
217
|
+
runningTimestamp: runningTimeStamp || _getTimeStamp(),
|
|
218
|
+
platform: os.platform(),
|
|
219
|
+
bitVersion: getHarmonyVersion(),
|
|
220
|
+
npmVersion: await getNpmVersion(),
|
|
221
|
+
yarnVersion: await getYarnVersion(),
|
|
222
|
+
userDetails: _getUserDetails(),
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
|
|
226
|
+
return env;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function _getUserDetails(): string {
|
|
230
|
+
const name = globalConfig.getSync(CFG_USER_NAME_KEY) || '';
|
|
231
|
+
const email = globalConfig.getSync(CFG_USER_EMAIL_KEY) || '';
|
|
232
|
+
return `${name}<${email}>`;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async function _getDebugLogAsBuffer(): Promise<Buffer | null | undefined> {
|
|
236
|
+
const exists = await fs.pathExists(DEBUG_LOG);
|
|
237
|
+
if (!exists) return null;
|
|
238
|
+
const log = await fs.readFile(DEBUG_LOG, 'utf-8');
|
|
239
|
+
const logWithoutChalk = removeChalkCharacters(log) as string;
|
|
240
|
+
return Buffer.from(logWithoutChalk);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function _getConsumerInfo(): Promise<ConsumerInfo | null | undefined> {
|
|
244
|
+
const consumerInfo = await getConsumerInfo(process.cwd());
|
|
245
|
+
return consumerInfo;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function _getBitMap(workspaceDir): Buffer | null | undefined {
|
|
249
|
+
return BitMap.loadRawSync(workspaceDir);
|
|
250
|
+
}
|
package/esm.mjs
ADDED
package/index.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DoctorAspect } from './doctor.aspect';
|
|
2
|
+
|
|
3
|
+
export type { DoctorMain } from './doctor.main.runtime';
|
|
4
|
+
export { DiagnosisNotFound } from './exceptions/diagnosis-not-found';
|
|
5
|
+
export { DIAGNOSIS_NAME_VALIDATE_GIT_EXEC } from './core-diagnoses/validate-git-exec';
|
|
6
|
+
export default DoctorAspect;
|
|
7
|
+
export { DoctorAspect };
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@teambit/doctor",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"componentId": {
|
|
6
|
+
"name": "doctor",
|
|
7
|
+
"version": "0.0.1",
|
|
8
|
+
"scope": "teambit.harmony"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"chalk": "2.4.2",
|
|
12
|
+
"table": "5.4.6",
|
|
13
|
+
"fs-extra": "10.0.0",
|
|
14
|
+
"tar-fs": "2.1.1",
|
|
15
|
+
"tar-stream": "2.2.0",
|
|
16
|
+
"glob": "7.1.6",
|
|
17
|
+
"lodash": "4.17.21",
|
|
18
|
+
"semver": "7.5.2",
|
|
19
|
+
"execa": "2.1.0",
|
|
20
|
+
"core-js": "^3.0.0",
|
|
21
|
+
"@babel/runtime": "7.20.0",
|
|
22
|
+
"@teambit/harmony": "0.4.6",
|
|
23
|
+
"@teambit/scope.modules.find-scope-path": "0.0.1",
|
|
24
|
+
"@teambit/component-id": "1.2.0",
|
|
25
|
+
"@teambit/bvm.list": "0.1.13",
|
|
26
|
+
"@teambit/bit-error": "0.0.404",
|
|
27
|
+
"@teambit/cli": "0.0.895"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/fs-extra": "9.0.7",
|
|
31
|
+
"@types/lodash": "4.14.165",
|
|
32
|
+
"@types/semver": "7.3.4",
|
|
33
|
+
"@types/node": "12.20.4",
|
|
34
|
+
"@types/react": "^17.0.8",
|
|
35
|
+
"@types/react-dom": "^17.0.5",
|
|
36
|
+
"@types/jest": "^26.0.0",
|
|
37
|
+
"@types/testing-library__jest-dom": "5.9.5"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@teambit/legacy": "1.0.716",
|
|
41
|
+
"react": "^16.8.0 || ^17.0.0",
|
|
42
|
+
"react-dom": "^16.8.0 || ^17.0.0"
|
|
43
|
+
},
|
|
44
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
45
|
+
"optionalDependencies": {},
|
|
46
|
+
"peerDependenciesMeta": {},
|
|
47
|
+
"exports": {
|
|
48
|
+
"node": {
|
|
49
|
+
"require": "./dist/index.js",
|
|
50
|
+
"import": "./dist/esm.mjs"
|
|
51
|
+
},
|
|
52
|
+
"default": "./dist/index.js"
|
|
53
|
+
}
|
|
54
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": [
|
|
4
|
+
"ES2022",
|
|
5
|
+
"DOM",
|
|
6
|
+
"DOM.Iterable",
|
|
7
|
+
"ScriptHost"
|
|
8
|
+
],
|
|
9
|
+
"target": "es2015",
|
|
10
|
+
"module": "CommonJS",
|
|
11
|
+
"jsx": "react",
|
|
12
|
+
"allowJs": true,
|
|
13
|
+
"composite": true,
|
|
14
|
+
"declaration": true,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"skipLibCheck": true,
|
|
17
|
+
"experimentalDecorators": true,
|
|
18
|
+
"outDir": "dist",
|
|
19
|
+
"moduleResolution": "node",
|
|
20
|
+
"esModuleInterop": true,
|
|
21
|
+
"rootDir": ".",
|
|
22
|
+
"resolveJsonModule": true,
|
|
23
|
+
"emitDeclarationOnly": true,
|
|
24
|
+
"emitDecoratorMetadata": true,
|
|
25
|
+
"allowSyntheticDefaultImports": true,
|
|
26
|
+
"strictPropertyInitialization": false,
|
|
27
|
+
"strict": true,
|
|
28
|
+
"noImplicitAny": false,
|
|
29
|
+
"preserveConstEnums": true
|
|
30
|
+
},
|
|
31
|
+
"exclude": [
|
|
32
|
+
"artifacts",
|
|
33
|
+
"public",
|
|
34
|
+
"dist",
|
|
35
|
+
"esm.mjs",
|
|
36
|
+
"node_modules",
|
|
37
|
+
"package.json",
|
|
38
|
+
"**/*.cjs"
|
|
39
|
+
],
|
|
40
|
+
"include": [
|
|
41
|
+
"**/*",
|
|
42
|
+
"**/*.json"
|
|
43
|
+
],
|
|
44
|
+
"references": []
|
|
45
|
+
}
|