-
Notifications
You must be signed in to change notification settings - Fork 795
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(telemetry) adding yarn 1 support, sanitizing data pre-flight #3082
Changes from 5 commits
932301a
3c379a8
5bcef46
0178d84
a2eacd5
64dcdc8
17878ba
dc3fa30
1b2084d
3869acf
1a5b657
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -107,7 +107,7 @@ export const prepareData = async ( | |
component_count: number = undefined | ||
): Promise<d.TrackableData> => { | ||
const { typescript, rollup } = coreCompiler.versions || { typescript: 'unknown', rollup: 'unknown' }; | ||
const { packages } = await getInstalledPackages(sys, config); | ||
const { packages, packages_no_versions } = await getInstalledPackages(sys, config); | ||
const targets = await getActiveTargets(config); | ||
const yarn = isUsingYarn(sys); | ||
const stencil = coreCompiler.version || 'unknown'; | ||
|
@@ -124,10 +124,12 @@ export const prepareData = async ( | |
component_count, | ||
targets, | ||
packages, | ||
packages_no_versions, | ||
arguments: config.flags.args, | ||
task: config.flags.task, | ||
stencil, | ||
system, | ||
system_major: getMajorVersion(system), | ||
os_name, | ||
os_version, | ||
cpu_model, | ||
|
@@ -139,24 +141,28 @@ export const prepareData = async ( | |
}; | ||
|
||
/** | ||
* Reads package-lock.json and package.json files in order to cross references the dependencies and devDependencies properties. Pull the current installed version of each package under the @stencil, @ionic, and @capacitor scopes. | ||
* Reads package-lock.json, yarn.lock, and package.json files in order to cross reference | ||
* the dependencies and devDependencies properties. Pulls up the current installed version | ||
* of each package under the @stencil, @ionic, and @capacitor scopes. | ||
* @returns string[] | ||
*/ | ||
async function getInstalledPackages(sys: d.CompilerSystem, config: d.Config): Promise<{ packages: string[] }> { | ||
async function getInstalledPackages( | ||
sys: d.CompilerSystem, | ||
config: d.Config | ||
): Promise<{ packages: string[]; packages_no_versions: string[] }> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we camelCase |
||
let packages: string[] = []; | ||
let packageLockJson: any; | ||
let packages_no_versions: string[] = []; | ||
const yarn = isUsingYarn(sys); | ||
|
||
try { | ||
// Read package.json and package-lock.json | ||
const appRootDir = sys.getCurrentDirectory(); | ||
|
||
const packageJson: d.PackageJsonData = await tryFn(readJson, sys.resolvePath(appRootDir + '/package.json')); | ||
|
||
packageLockJson = await tryFn(readJson, sys.resolvePath(appRootDir + '/package-lock.json')); | ||
const packageJson: d.PackageJsonData = await tryFn(readJson, sys, sys.resolvePath(appRootDir + '/package.json')); | ||
|
||
// They don't have a package.json for some reason? Eject button. | ||
if (!packageJson) { | ||
return { packages }; | ||
return { packages, packages_no_versions }; | ||
} | ||
|
||
const rawPackages: [string, string][] = Object.entries({ | ||
|
@@ -170,20 +176,67 @@ async function getInstalledPackages(sys: d.CompilerSystem, config: d.Config): Pr | |
([k]) => k.startsWith('@stencil/') || k.startsWith('@ionic/') || k.startsWith('@capacitor/') | ||
); | ||
|
||
packages = packageLockJson | ||
? ionicPackages.map( | ||
([k, v]) => | ||
`${k}@${packageLockJson?.dependencies[k]?.version ?? packageLockJson?.devDependencies[k]?.version ?? v}` | ||
) | ||
: ionicPackages.map(([k, v]) => `${k}@${v}`); | ||
try { | ||
packages = yarn ? await yarnPackages(sys, ionicPackages) : await npmPackages(sys, ionicPackages); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For my own knowledge, in what cases do we expect either of these There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the lock files cannot be read (doesn't exist/incorrect file structure), that's when these should throw. |
||
} catch (e) { | ||
packages = ionicPackages.map(([k, v]) => `${k}@${v.replace('^', '')}`); | ||
} | ||
|
||
packages_no_versions = ionicPackages.map(([k]) => `${k}`); | ||
|
||
return { packages }; | ||
return { packages, packages_no_versions }; | ||
} catch (err) { | ||
hasDebug(config) && console.error(err); | ||
return { packages }; | ||
return { packages, packages_no_versions }; | ||
} | ||
} | ||
|
||
/** | ||
* Visits the npm lock file to find the exact versions that are installed | ||
* @param sys The system where the command is invoked | ||
* @param ionicPackages a list of the found packages matching `@stencil`, `@capacitor`, or `@ionic` from the package.json file. | ||
* @returns an array of strings of all the packages and their versions. | ||
*/ | ||
async function npmPackages(sys: d.CompilerSystem, ionicPackages: [string, string][]) { | ||
splitinfinities marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const appRootDir = sys.getCurrentDirectory(); | ||
const packageLockJson: any = await tryFn(readJson, sys, sys.resolvePath(appRootDir + '/package-lock.json')); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should use |
||
|
||
return ionicPackages.map(([k, v]) => { | ||
let version = packageLockJson?.dependencies[k]?.version ?? packageLockJson?.devDependencies[k]?.version ?? v; | ||
version = version.includes('file:') ? sanitizeDeclaredVersion(v) : version; | ||
return `${k}@${version}`; | ||
}); | ||
} | ||
|
||
/** | ||
* Visits the yarn lock file to find the exact versions that are installed | ||
* @param sys The system where the command is invoked | ||
* @param ionicPackages a list of the found packages matching `@stencil`, `@capacitor`, or `@ionic` from the package.json file. | ||
* @returns an array of strings of all the packages and their versions. | ||
*/ | ||
async function yarnPackages(sys: d.CompilerSystem, ionicPackages: [string, string][]) { | ||
splitinfinities marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const appRootDir = sys.getCurrentDirectory(); | ||
const yarnLock = sys.readFileSync(sys.resolvePath(appRootDir + '/yarn.lock')); | ||
const packageLockJson = sys.parseYarnLockFile(yarnLock); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we rename this to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you walk me through the success/failure cases of this being read? Will There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If reading fails, it throws and resolves back to the parent try/catch block. All other paths are truthy as you say. |
||
|
||
return ionicPackages.map(([k, v]) => { | ||
const identifiedVersion = `${k}@${v}`; | ||
let version = packageLockJson.object[identifiedVersion]?.version; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We would handle that above, within the getInstalledPackages try/catch block. |
||
version = version.includes('undefined') ? sanitizeDeclaredVersion(identifiedVersion) : version; | ||
return `${k}@${version}`; | ||
}); | ||
} | ||
|
||
/** | ||
* This function is used for fallback purposes, where an npm or yarn lock file doesn't exist in the consumers directory. | ||
* This will strip away ^ and ~ from the declared package versions in a package.json. | ||
splitinfinities marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* @param version the raw semver pattern identifier version string | ||
* @returns a cleaned up representation without any qualifiers | ||
*/ | ||
function sanitizeDeclaredVersion(version: string) { | ||
splitinfinities marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return version.replace(/[*^~]/g, ''); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is doing a global replace, which is probably fine? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that was the intent |
||
} | ||
|
||
/** | ||
* If telemetry is enabled, send a metric via IPC to a forked process for uploading. | ||
*/ | ||
|
@@ -287,3 +340,13 @@ export async function enableTelemetry(sys: d.CompilerSystem): Promise<boolean> { | |
export async function disableTelemetry(sys: d.CompilerSystem): Promise<boolean> { | ||
return await updateConfig(sys, { 'telemetry.stencil': false }); | ||
} | ||
|
||
/** | ||
* Takes in a semver string in order to return the major version. | ||
* @param version The fully qualified semver version | ||
* @returns a string of the major version | ||
*/ | ||
function getMajorVersion(version: string): string { | ||
const parts = version.split('.'); | ||
return parts[0]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add
@yarnpkg/lockfile
to https://github.com/ionic-team/stencil/blob/66d0476bb8acff5225926cc50769db16a5fd8ed3/scripts/license.ts#L12There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a dev dependency, how is this getting rolled up and put in the final compiler output?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a part of the compiler process, since anything within the node sys gets bundled up and shipped. Similar to how we bundle TypeScript or Rollup.