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

consolidated @lando/core and @lando/cli updates into a singular lando… #299

Merged
merged 3 commits into from
Dec 11, 2024
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## {{ UNRELEASED_VERSION }} - [{{ UNRELEASED_DATE }}]({{ UNRELEASED_LINK }})

* Consolidated `@lando/core` and `@lando/cli` updates into a singular `lando` update

## v3.24.0-beta.6 - [December 11, 2024](https://github.com/lando/core/releases/tag/v3.24.0-beta.6)

* Optimized deps part 2
Expand Down
8 changes: 4 additions & 4 deletions docs/cli/version.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Displays lando version information.
## Usage

```sh
lando version [--all] [--component <component>] [--full]
lando version [--all] [--full] [--plugin <plugin>]
```

## Options
Expand All @@ -22,8 +22,8 @@ lando version [--all] [--component <component>] [--full]
--help Shows lando or delegated command help if applicable [boolean]
--verbose, -v Runs with extra verbosity [count]
--all, -a Shows all version information [boolean]
--component, -c Shows version info for specific component [string] [default: "@lando/core"]
--full, -f Shows full version string [boolean]
--plugin, -p Shows version info for specific plugin [string]
```

## Examples
Expand All @@ -36,8 +36,8 @@ lando version --all
lando version --full

# Show version information for the cli
lando version --component @lando/cli
lando version --plugin @lando/php

# Do the same as above but in component shorthand
lando version --component cli
lando version --plugin php
```
2 changes: 1 addition & 1 deletion examples/certs/.lando.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ services:
- 8080/http
curl:
api: 4
image: curlimages/curl
image: curlimages/curl:8.10.1
command: sleep infinity

tooling:
Expand Down
8 changes: 4 additions & 4 deletions examples/version/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ lando version | grep "$(lando version --component core)"

# Should print all version information with --all
lando version --all
lando version --all | grep @lando/core | grep "$(lando version --component @lando/core)"
lando version --all | grep lando | grep "$(lando version --component @lando/core)"
lando version --all | grep @lando/base-test-plugin-2 | grep v1.0.2
lando version -a | grep @lando/core | grep v3
lando version -a | grep lando | grep v3

# Should print specific component information
lando version --component @lando/base-test-plugin-2 | grep v1.0.2
lando version -c base-test-plugin-2 | grep v1.0.2
lando version --plugin base-test-plugin-2 | grep v1.0.2

# Should print full version information
lando version --full
lando version --full | grep @lando/core | grep "$(lando version -c core)" | grep "$(lando config --path os.platform | tr -d '\n' | sed -e "s/^'//" -e "s/'$//")" | grep "$(lando config --path os.arch | tr -d '\n' | sed -e "s/^'//" -e "s/'$//")" | grep node-v20 | grep cli | grep "$(lando version -c cli)"
lando version --full | grep "$(lando version -c core)" | grep "$(lando config --path os.platform | tr -d '\n' | sed -e "s/^'//" -e "s/'$//")" | grep "$(lando config --path os.arch | tr -d '\n' | sed -e "s/^'//" -e "s/'$//")" | grep node-v20
```

## Destroy tests
Expand Down
183 changes: 79 additions & 104 deletions lib/updates.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ module.exports = class UpdateManager {
this.dir = dir;
this.debug = debug;

// store "special" lando update metainfo here
this.lando = undefined;
// some state stuff
this.hasChecked = false;
}
Expand Down Expand Up @@ -80,115 +82,81 @@ module.exports = class UpdateManager {
*/
async check() {
// Start with our basic checks
const checks = this.plugins.map(async plugin => {
try {
await plugin.check4Update();
return plugin;
} catch {
return plugin;
}
});
// NOTE: that we do not include core if its being loaded by the CLI
const checks = this.plugins
.filter(plugin => plugin.location !== this?.cli?.plugin)
.map(async plugin => {
try {
await plugin.check4Update();
return plugin;
} catch {
return plugin;
}
});

// special handling for CLI, push cli check here
if (this.cli && this.cli.plugin) {
const Plugin = getPluginClass({channel: this.channel, config: this.config, debug: this.debug});
const cli = this.cli;
this._cli = new Plugin(cli.plugin);
const lando = new Plugin(cli.plugin);

// update data
this._cli.name = '@lando/cli';
this._cli.isCli = true;
this._cli.isUpdateable = cli.packaged && !cli.source;
this._cli.installPath = cli.installPath;
this.internalCore = cli.coreBase;
this.internalCoreVersion = cli.coreBaseVersion;
lando.name = 'lando';
lando.isCli = true;
lando.isUpdateable = cli.packaged && !cli.source;
lando.installPath = cli.installPath;
lando.internalCore = cli.coreBase;
lando.internalCoreVersion = cli.coreBaseVersion;

// handle 3.21.0-beta18 release snafu
if (this._cli.version === '3.21.0-beta18') {
this._cli.spec = '@lando/[email protected]';
this._cli.version = '3.21.0-beta.18';
this._cli.pjson.version = '3.21.0-beta.18';
if (lando.version === '3.21.0-beta18') {
lando.spec = '@lando/[email protected]';
lando.version = '3.21.0-beta.18';
lando.pjson.version = '3.21.0-beta.18';
}

checks.push(new Promise(async resolve => { // eslint-disable-line no-async-promise-executor
// summon the katkraken
const octokit = getOctokit({auth: get(process, 'env.LANDO_GITHUB_TOKEN'), userAgent: this.agent});
// just a helper to give consistent prez
const extra = color.dim('@lando/cli');

// go for it
checks.push((async () => {
try {
if (!this._cli.isUpdateable) {
this.debug(`${extra} is not updateable, update manually`);
resolve(this._cli);
return;
}
// assess whether core has an update
await lando.check4Update();

const {data, status, url} = await octokit.rest.repos.listReleases({owner: 'lando', repo: 'core'});
this.debug('retrieved cli information from %o [%o]', url, status);

const versions = data
.map(release => ({...release, version: semver.clean(release.tag_name)}))
.filter(release => semver.valid(release.version) !== null)
.filter(release => semver.satisfies(release.version, '>=3.0.0 <4', {loose: true, includePrerelease: true}))
.filter(release => release.draft === false)
.filter(release => this.channel === 'edge' ? true : release.prerelease === false)
.map(release => release.version);

// get highest version
const hv = semver.rsort(versions)[0];

// cli cannot be updated
if (require('../utils/is-lte-version')(hv, this._cli.version)) {
this.debug(`${extra} cannot be updated on channel %o (%o <= %o)`, this.channel, hv, this._cli.version);
resolve(this._cli);
return;

// otherwise update is available
} else {
const arch = ['arm64', 'aarch64'].includes(process.arch) ? 'arm64' : 'x64';
const os = getOS();
const ext = process.platform === 'win32' ? '.exe' : '';

// @NOTE: should this always work?
const release = data.find(release => release.tag_name === `v${hv}`);
release.version = hv;
release.binary = `lando-${os}-${arch}-v${release.version}${ext}`;
release.channel = release.prerelease ? 'edge' : 'stable';
// @NOTE: ditto
const asset = release.assets.find(asset => asset.name === release.binary);

// if we have the needed asset then update is available
// @NOTE: this check is required because the release can post before the cli binaries
// are avilable
if (asset?.url) {
release.download = asset.browser_download_url;
this._cli.updateAvailable = `@lando/cli@${hv}`;
this._cli.update = release;
this.debug(
`${extra} can be updated to %o on channel %o (%o > %o)`,
release.download,
this.channel,
hv,
this._cli.version,
);
}
// if no update then just return quickly
if (!lando.updateAvailable) return lando;

resolve(this._cli);
}
// otherwise we need to match an update to a link we can check
const arch = ['arm64', 'aarch64'].includes(process.arch) ? 'arm64' : 'x64';
const ext = process.platform === 'win32' ? '.exe' : '';
const os = getOS();
const version = `v${lando.update.version}`;
const url = `https://github.com/lando/core/releases/download/${version}/lando-${os}-${arch}-${version}${ext}`;
this.debug(`${color.dim('lando')} update resolved cli download url to %o`, url);

// error has occured
// now see whether that link is good
const {status, statusText} = await axios.head(url, {validateStatus: () => true});

// if we are good set the update URL
if (status === 200) {
this.lando = lando;
this.lando.update.url = url;

// if we are NOT good then the update is not available
} else lando.updateAvailable = false;

// also log
this.debug(`${color.dim('lando')} download url %o returned %o %o`, url, status, statusText);

return lando;
} catch (error) {
if (error.status) error.message = `${error.message} [${error.status}]`;
if (error.response && error.response.url) error.message = `${error.message} (${error.response.url})`;
this.debug(`${extra} could not get update info, error: %o`, error.message);
this.debug(`${color.dim('lando')} could not get update info, error: %o`, error.message);
this.debug('%j', error);
this._cli.isUpdateable = false;
this._cli.updateAvailable = false;
this._cli.update = {error};
resolve(this._cli);
lando.isUpdateable = false;
lando.updateAvailable = false;
lando.update = {error};
return lando;
}
}));
})());
}

// run all checks and return
Expand Down Expand Up @@ -217,28 +185,30 @@ module.exports = class UpdateManager {
.map(task => require('../utils/parse-setup-task')(task));

// push cli check here
if (get(this, '_cli.update.download')) {
if (this?.lando?.update?.url) {
// get stuff
const {installPath, update} = this.lando;
const {url, version} = update;

tasks.push(require('../utils/parse-setup-task')({
title: `Updating @lando/cli to v${this._cli.update.version}`,
description: '@lando/cli',
title: `Updating lando to v${version}`,
description: 'lando',
canInstall: async () => {
// check if user can write to install path
try {
fs.accessSync(this._cli.installPath, fs.constants.W_OK);
fs.accessSync(installPath, fs.constants.W_OK);
} catch {
throw new Error(`Lando cannot write to ${this._cli.installPath}!`);
throw new Error(`Lando cannot write to ${installPath}!`);
}

// throw error if we cannot ping the download link
await axios.head(this._cli.update.download);
await axios.head(url);

// or true
return true;
},
task: async (ctx, task) => new Promise((resolve, reject) => {
const cacheDir = require('../utils/get-cache-dir')('lando');
const url = this._cli.update.download;
const version = this._cli.update.version;
const filename = process.platform === 'win32' ? 'lando.exe' : 'lando';
const dest = path.join(cacheDir, `v${version}`, 'bin', filename);
// @TODO: restore test when we cut 3.22?
Expand All @@ -247,21 +217,26 @@ module.exports = class UpdateManager {
// success
download.on('done', async data => {
// refresh the "symlink"
require('../utils/link-bin')(this._cli.installPath, dest, {debug: this.debug});
require('../utils/link-bin')(installPath, dest, {debug: this.debug});

// set a good default update messag
task.title = `Updated @lando/cli to ${version}`;
task.title = `Updated lando to ${version}`;

// if lando.exe exists on windows in the install path then remove it so the link has primacy
// in PATHEXT hierarchy
if (process.platform === 'win32' && fs.existsSync(path.join(this._cli.installPath, filename))) {
remove(path.join(this._cli.installPath, filename));
if (process.platform === 'win32' && fs.existsSync(path.join(installPath, filename))) {
remove(path.join(installPath, filename));
}

// also remove lando/@core if it exists in the plugins directory
if (fs.existsSync(path.join(this.dir, '@lando', 'core'))) {
remove(path.join(this.dir, '@lando', 'core'));
}

// if link is not in PATH then attempt to add it
// @NOTE: feels sufficient to just check for `lando` since it _should_ exist in win and posix
if (!require('../utils/is-in-path')(path.join(this._cli.installPath, 'lando'))) {
const binPaths = require('../utils/get-bin-paths')(this._cli);
if (!require('../utils/is-in-path')(path.join(installPath, 'lando'))) {
const binPaths = require('../utils/get-bin-paths')(this.lando);
const shellEnv = require('../utils/get-shellenv')(binPaths);

// special handling for cmd.exe
Expand Down Expand Up @@ -294,7 +269,7 @@ module.exports = class UpdateManager {
});
// update title to reflect download progress
download.on('progress', progress => {
task.title = `Downloading @lando/cli@${version} ${color.dim(`[${progress.percentage}%]`)}`;
task.title = `Downloading lando@${version} ${color.dim(`[${progress.percentage}%]`)}`;
});
}),
}));
Expand Down
Loading
Loading