Skip to content

Commit

Permalink
Check for newer skuba versions (#300)
Browse files Browse the repository at this point in the history
  • Loading branch information
72636c authored Dec 14, 2020
1 parent ceb394f commit e1dab09
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 16 deletions.
7 changes: 7 additions & 0 deletions .changeset/thick-dancers-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'skuba': minor
---

**configure, help, init:** Check for newer skuba versions

skuba will now print an upgrade command if there is a newer version available. You can now use a global installation without worrying that you're setting up new repos using outdated templates.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ To bootstrap an existing project:
npx skuba configure
```

**skuba** supports a global installation to speed up local development:

```shell
yarn global add skuba

# Look, no `npx`!
skuba version
```

## CLI reference

**skuba** commands are typically found in the `scripts` section of `package.json`.
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"fs-extra": "^9.0.1",
"get-port": "^5.1.1",
"ignore": "^5.1.8",
"is-installed-globally": "^0.3.2",
"jest": "^26.6.0",
"latest-version": "^5.1.0",
"lodash.mergewith": "^4.6.2",
Expand Down
4 changes: 2 additions & 2 deletions src/cli/configure/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Select } from 'enquirer';
import { createInclusionFilter } from '../../utils/copy';
import { createExec, ensureCommands } from '../../utils/exec';
import { log } from '../../utils/logging';
import { showLogo } from '../../utils/logo';
import { showLogoAndVersionInfo } from '../../utils/logo';
import { BASE_TEMPLATE_DIR } from '../../utils/template';
import { hasProp } from '../../utils/validation';

Expand All @@ -30,7 +30,7 @@ const shouldApply = async (name: string) => {
};

export const configure = async () => {
await showLogo();
await showLogoAndVersionInfo();

const [manifest] = await Promise.all([
getDestinationManifest(),
Expand Down
4 changes: 2 additions & 2 deletions src/cli/help.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { showHelp } from '../utils/help';
import { showLogo } from '../utils/logo';
import { showLogoAndVersionInfo } from '../utils/logo';

export const help = async () => {
await showLogo();
await showLogoAndVersionInfo();

showHelp();
};
8 changes: 4 additions & 4 deletions src/cli/init/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from '../../utils/copy';
import { createExec, ensureCommands } from '../../utils/exec';
import { log } from '../../utils/logging';
import { showLogo } from '../../utils/logo';
import { showLogoAndVersionInfo } from '../../utils/logo';
import {
BASE_TEMPLATE_DIR,
ensureTemplateConfigDeletion,
Expand All @@ -18,7 +18,7 @@ import { commitChanges, initialiseRepo } from './git';
import { writePackageJson } from './writePackageJson';

export const init = async () => {
const skubaVersion = await showLogo();
const skubaVersionInfo = await showLogoAndVersionInfo();

await ensureCommands('git', 'yarn');

Expand Down Expand Up @@ -66,7 +66,7 @@ export const init = async () => {
entryPoint,
template: templateName,
type,
version: skubaVersion,
version: skubaVersionInfo.local,
}),
]);

Expand All @@ -86,7 +86,7 @@ export const init = async () => {
'--dev',
'--exact',
'--silent',
`skuba@${skubaVersion}`,
`skuba@${skubaVersionInfo.local}`,
);

await commitChanges(exec, `Clone ${templateName}`);
Expand Down
4 changes: 2 additions & 2 deletions src/skuba.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { COMMAND_DIR, COMMAND_SET, commandToModule } from './utils/command';
import { handleCliError } from './utils/error';
import { showHelp } from './utils/help';
import { log } from './utils/logging';
import { showLogo } from './utils/logo';
import { showLogoAndVersionInfo } from './utils/logo';
import { hasProp } from './utils/validation';

const skuba = async () => {
Expand All @@ -43,7 +43,7 @@ const skuba = async () => {
}

log.err(log.bold(commandName), 'is not recognised as a command.');
await showLogo();
await showLogoAndVersionInfo();
showHelp();

process.exit(1);
Expand Down
31 changes: 26 additions & 5 deletions src/utils/logo.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import chalk from 'chalk';
import isInstalledGlobally from 'is-installed-globally';

import { log } from './logging';
import { getSkubaVersion } from './version';
import { getSkubaVersionInfo } from './version';

const LOGO = chalk.blueBright(`
╭─╮ ${chalk.magentaBright(' ')}╭─╮
Expand All @@ -10,12 +11,32 @@ const LOGO = chalk.blueBright(`
╰───╰─┴─${chalk.magentaBright('╰───╯')}───╯── ╰
`);

export const showLogo = async () => {
const skubaVersion = await getSkubaVersion();
export const showLogoAndVersionInfo = async () => {
const versionInfo = await getSkubaVersionInfo();

log.plain(LOGO);
log.subtle(skubaVersion);
log.subtle(
log.bold(versionInfo.local),
'|',
'latest',
log.bold(versionInfo.latest ?? 'offline ✈'),
);
log.newline();

return skubaVersion;
if (versionInfo.isStale) {
log.warn('Your skuba installation is out of date.');
log.warn('Consider upgrading:');
log.newline();
log.warn(
log.bold(
'yarn',
...(isInstalledGlobally ? ['global'] : []),
'upgrade',
`skuba@${versionInfo.latest}`,
),
);
log.newline();
}

return versionInfo;
};
52 changes: 52 additions & 0 deletions src/utils/version.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,59 @@
import latestVersion from 'latest-version';

import { getSkubaManifest } from './manifest';

const sleep = (ms: number) =>
new Promise<void>((resolve) => setTimeout(resolve, ms));

const latestSkubaVersion = async (): Promise<string | null> => {
try {
// Don't pull an Apple; bail out before holding up the command for too long
const result = await Promise.race([latestVersion('skuba'), sleep(2_000)]);

return typeof result === 'string' ? result : null;
} catch {
return null;
}
};

export const getSkubaVersion = async (): Promise<string> => {
const { version } = await getSkubaManifest();

return version;
};

type SkubaVersionInfo =
| {
isStale: true;

local: string;
latest: string;
}
| {
isStale: false;

local: string;
latest: string | null;
};

export const getSkubaVersionInfo = async (): Promise<SkubaVersionInfo> => {
const [local, latest] = await Promise.all([
getSkubaVersion(),
latestSkubaVersion(),
]);

if (latest === null) {
// Assume we're up to date if we can't reach the npm registry
return {
isStale: false,
local,
latest,
};
}

return {
isStale: latest !== local,
local,
latest,
};
};
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5160,7 +5160,7 @@ is-installed-globally@^0.1.0:
global-dirs "^0.1.0"
is-path-inside "^1.0.0"

is-installed-globally@^0.3.1:
is-installed-globally@^0.3.1, is-installed-globally@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141"
integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==
Expand Down

0 comments on commit e1dab09

Please sign in to comment.