Skip to content
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

Merged
merged 8 commits into from
Nov 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 0 additions & 118 deletions __tests__/commands/self-update.js

This file was deleted.

1 change: 1 addition & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ deployment:
commands:
- ~/ghr/ghr --username yarnpkg --repository yarn --token $KPM_CIRCLE_RELEASE_TOKEN v$(dist/bin/yarn --version) artifacts/
- echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
- ./scripts/set-installation-method.js "`pwd`/package.json" npm
- npm publish

notify:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"inquirer": "^1.2.2",
"invariant": "^2.2.0",
"is-builtin-module": "^1.0.0",
"is-ci": "^1.0.9",
"is-ci": "^1.0.10",
"leven": "^2.0.0",
"loud-rejection": "^1.2.0",
"minimatch": "^3.0.3",
Expand Down
22 changes: 19 additions & 3 deletions scripts/install-latest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,25 @@ yarn_install() {
printf "${white}Installing Yarn!$reset\n"

if [ -d "$HOME/.yarn" ]; then
printf "$red> ~/.yarn already exists, possibly from a past Yarn install.$reset\n"
printf "$red> Remove it (rm -rf ~/.yarn) and run this script again.$reset\n"
exit 0
if [ -n `which yarn` ]; then
if [ "$1" = '--nightly' ]; then
latest_url=https://nightly.yarnpkg.com/latest-tar-version
else
latest_url=https://yarnpkg.com/latest-version
fi
LATEST_VERSION=`curl $latest_url`
YARN_VERSION=`yarn -V`

if [ "$LATEST_VERSION" -eq "$YARN_VERSION" ]; then
printf "$green> Yarn is already at the latest version.$reset\n"
else
rm -rf "$HOME/.yarn"
Copy link
Member

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)"

Copy link
Member

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?

fi
else
printf "$red> ~/.yarn already exists, possibly from a past Yarn install.$reset\n"
printf "$red> Remove it (rm -rf ~/.yarn) and run this script again.$reset\n"
exit 0
fi
fi

yarn_get_tarball $1
Expand Down
1 change: 0 additions & 1 deletion src/cli/commands/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import * as pack from './pack.js'; export {pack};
import * as publish from './publish.js'; export {publish};
import * as remove from './remove.js'; export {remove};
import * as run from './run.js'; export {run};
import * as selfUpdate from './self-update.js'; export {selfUpdate};
import * as tag from './tag.js'; export {tag};
import * as team from './team.js'; export {team};
import * as unlink from './unlink.js'; export {unlink};
Expand Down
117 changes: 117 additions & 0 deletions src/cli/commands/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

possibly typo verison

const ONE_DAY = 1000 * 60 * 60 * 24;

export type InstallCwdRequest = [
DependencyRequestPatterns,
Expand Down Expand Up @@ -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';
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add Chocolatey: choco upgrade yarn

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
Expand Down Expand Up @@ -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'));
Expand Down Expand Up @@ -354,6 +404,7 @@ export class Install {

// fin!
await this.saveLockfileAndIntegrity(patterns);
this.maybeOutputUpdate();
this.config.requestManager.clearCache();
return patterns;
}
Expand Down Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The 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
Copy link
Member

Choose a reason for hiding this comment

The 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',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to better automate this getting updated

Copy link
Member

Choose a reason for hiding this comment

The 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));
Copy link
Member

Choose a reason for hiding this comment

The 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 update-notifier does?

}
}
};
}
}

/**
* Method to override with a possible upgrade message.
*/

maybeOutputUpdate() {}
maybeOutputUpdate: any;
}

export function setFlags(commander: Object) {
Expand Down
Loading