/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format */ import {HealthcheckResult} from '../reducers/healthchecks'; import {getHealthchecks, getEnvInfo, Healthchecks} from 'flipper-doctor'; import {logPlatformSuccessRate, reportPlatformFailures} from 'flipper-common'; let healthcheckIsRunning: boolean; let runningHealthcheck: Promise; export type HealthcheckEventsHandler = { updateHealthcheckResult: ( categoryKey: string, itemKey: string, result: HealthcheckResult, ) => void; startHealthchecks: (healthchecks: Healthchecks) => void; finishHealthchecks: () => void; }; export type HealthcheckSettings = { settings: { enableAndroid: boolean; enableIOS: boolean; enablePhysicalIOS: boolean; idbPath: string; }; }; export type HealthcheckOptions = HealthcheckEventsHandler & HealthcheckSettings; async function launchHealthchecks(options: HealthcheckOptions): Promise { const healthchecks = getHealthchecks(); if (!options.settings.enableAndroid) { healthchecks.android = { label: healthchecks.android.label, isSkipped: true, skipReason: 'Healthcheck is skipped, because "Android Development" option is disabled in the Flipper settings', }; } if (!options.settings.enableIOS) { healthchecks.ios = { label: healthchecks.ios.label, isSkipped: true, skipReason: 'Healthcheck is skipped, because "iOS Development" option is disabled in the Flipper settings', }; } options.startHealthchecks(healthchecks); const environmentInfo = await getEnvInfo(); let hasProblems = false; for (const [categoryKey, category] of Object.entries(healthchecks)) { if (category.isSkipped) { continue; } for (const h of category.healthchecks) { const checkResult = await h.run(environmentInfo, options.settings); const metricName = `doctor:${h.key.replace('.', ':')}.healthcheck`; // e.g. "doctor:ios:xcode-select.healthcheck" if (checkResult.hasProblem) { hasProblems = true; logPlatformSuccessRate(metricName, { kind: 'failure', supportedOperation: true, error: null, }); } else { logPlatformSuccessRate(metricName, { kind: 'success', }); } const result: HealthcheckResult = checkResult.hasProblem && h.isRequired ? { status: 'FAILED', message: checkResult.message, } : checkResult.hasProblem && !h.isRequired ? { status: 'WARNING', message: checkResult.message, } : {status: 'SUCCESS', message: checkResult.message}; options.updateHealthcheckResult(categoryKey, h.key, result); } } options.finishHealthchecks(); if (hasProblems) { logPlatformSuccessRate('doctor.healthcheck', { kind: 'failure', supportedOperation: true, error: null, }); } else { logPlatformSuccessRate('doctor.healthcheck', { kind: 'success', }); } } export default async function runHealthchecks( options: HealthcheckOptions, ): Promise { if (healthcheckIsRunning) { return runningHealthcheck; } runningHealthcheck = reportPlatformFailures( launchHealthchecks(options), 'doctor:runHealthchecks', ); return runningHealthcheck; }