-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Add automatic check for updates that nags the user when there's a new version available #1429
Changes from all commits
e864da9
6e707f3
6c41fee
e2aa1d6
f4c2fe6
6e89da4
0e81f3f
ef68b73
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,8 +26,15 @@ import map from '../../util/map.js'; | |
import {sortAlpha} from '../../util/misc.js'; | ||
|
||
const invariant = require('invariant'); | ||
const userHome = require('user-home'); | ||
const semver = require('semver'); | ||
const emoji = require('node-emoji'); | ||
const isCI = require('is-ci'); | ||
const path = require('path'); | ||
const fs2 = require('fs'); | ||
|
||
const {verison: YARN_VERSION, installationMethod: YARN_INSTALL_METHOD} = require('../../../package.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. possibly typo |
||
const ONE_DAY = 1000 * 60 * 60 * 24; | ||
|
||
export type InstallCwdRequest = [ | ||
DependencyRequestPatterns, | ||
|
@@ -64,6 +71,47 @@ type Flags = { | |
tilde: boolean, | ||
}; | ||
|
||
/** | ||
* Try and detect the installation method for Yarn and provide a command to update it with. | ||
*/ | ||
|
||
function getUpdateCommand(): ?string { | ||
if (YARN_INSTALL_METHOD === 'tar') { | ||
return 'curl -o- -L https://yarnpkg.com/install.sh | bash'; | ||
} | ||
|
||
if (YARN_INSTALL_METHOD === 'homebrew') { | ||
return 'brew upgrade yarn'; | ||
} | ||
|
||
if (YARN_INSTALL_METHOD === 'deb') { | ||
return 'sudo apt-get update && sudo apt-get install yarn'; | ||
} | ||
|
||
if (YARN_INSTALL_METHOD === 'rpm') { | ||
return 'sudo yum install yarn'; | ||
} | ||
|
||
if (YARN_INSTALL_METHOD === 'npm') { | ||
return 'npm upgrade --global yarn'; | ||
} | ||
|
||
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. Also add Chocolatey: |
||
if (YARN_INSTALL_METHOD === 'chocolatey') { | ||
return 'choco upgrade yarn'; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
function getUpdateInstaller(): ?string { | ||
// Windows | ||
if (YARN_INSTALL_METHOD === 'msi') { | ||
return 'https://yarnpkg.com/latest.msi'; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
function normalizeFlags(config: Config, rawFlags: Object): Flags { | ||
const flags = { | ||
// install | ||
|
@@ -277,6 +325,8 @@ export class Install { | |
*/ | ||
|
||
async init(): Promise<Array<string>> { | ||
this.checkUpdate(); | ||
|
||
// warn if we have a shrinkwrap | ||
if (await fs.exists(path.join(this.config.cwd, 'npm-shrinkwrap.json'))) { | ||
this.reporter.error(this.reporter.lang('shrinkwrapWarning')); | ||
|
@@ -354,6 +404,7 @@ export class Install { | |
|
||
// fin! | ||
await this.saveLockfileAndIntegrity(patterns); | ||
this.maybeOutputUpdate(); | ||
this.config.requestManager.clearCache(); | ||
return patterns; | ||
} | ||
|
@@ -634,6 +685,72 @@ export class Install { | |
|
||
return request; | ||
} | ||
|
||
/** | ||
* Check for updates every day and output a nag message if there's a newer version. | ||
*/ | ||
|
||
checkUpdate() { | ||
if (!process.stdout.isTTY || isCI) { | ||
// don't show upgrade dialog on CI or non-TTY terminals | ||
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. I think this is still valuable for non-TTY environments. Why should we avoid showing a notice about Yarn being outdated just because the user is piping the output to a file, for example? |
||
return; | ||
} | ||
|
||
// only check for updates once a day | ||
const lastUpdateCheck = Number(this.config.getOption('lastUpdateCheck')) || 0; | ||
if (lastUpdateCheck && Date.now() - lastUpdateCheck < ONE_DAY) { | ||
return; | ||
} | ||
|
||
// don't bug for updates on tagged releases | ||
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. Hmm, I wonder if we should bug on nightly builds? |
||
if (YARN_VERSION.indexOf('-') >= 0) { | ||
return; | ||
} | ||
|
||
this._checkUpdate().catch(() => { | ||
// swallow errors | ||
}); | ||
} | ||
|
||
async _checkUpdate(): Promise<void> { | ||
let latestVersion = await this.config.requestManager.request({ | ||
url: 'https://yarnpkg.com/latest-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. We need to better automate this getting updated 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. Yeah, I'm going to have a webhook that runs when releases are updated, or just a cronjob. The tricky thing is that we can't bump the version number until we verify that all files are attached to the release, and the Windows installer is attached separately from everything else (as it's built on AppVeyor). |
||
}); | ||
invariant(typeof latestVersion === 'string', 'expected string'); | ||
latestVersion = latestVersion.trim(); | ||
if (!semver.valid(latestVersion)) { | ||
return; | ||
} | ||
|
||
// ensure we only check for updates periodically | ||
this.config.registries.yarn.saveHomeConfig({ | ||
lastUpdateCheck: Date.now(), | ||
}); | ||
|
||
if (semver.gt(latestVersion, YARN_VERSION)) { | ||
this.maybeOutputUpdate = () => { | ||
this.reporter.warn(this.reporter.lang('yarnOutdated', latestVersion, YARN_VERSION)); | ||
|
||
const command = getUpdateCommand(); | ||
if (command) { | ||
this.reporter.info(this.reporter.lang('yarnOutdatedCommand')); | ||
this.reporter.command(command); | ||
} else { | ||
const installer = getUpdateInstaller(); | ||
if (installer) { | ||
this.reporter.info(this.reporter.lang('yarnOutdatedInstaller', installer)); | ||
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. Optional, but can we use something like boxen (or just render the ANSI codes ourself) to render a fancy box around it, like |
||
} | ||
} | ||
}; | ||
} | ||
} | ||
|
||
/** | ||
* Method to override with a possible upgrade message. | ||
*/ | ||
|
||
maybeOutputUpdate() {} | ||
maybeOutputUpdate: any; | ||
} | ||
|
||
export function setFlags(commander: Object) { | ||
|
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.
2scary4me, maybe warn the user before doing this.
"A newer version of Yarn is available, do you want to delete the existing version and upgrade? (Y/N)"
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.
Also won't this blow away their config? Or is that stored elsewhere?