This change makes Appium recognize the existence of an extension in the current (or parent) dir, and automatically adds it to the extension manifest.
Resolution of Appium (e.g., _how_ Appium was installed) is no longer taken into account when determining if we're "in" a package that depends upon Appium. So you can easily `npm link appium` in an extension working copy if you wish, and this will not impact Appium's behavior.
To support this change, `hasAppiumDependency()` in `@appium/support`'s `env` has changed to be a wrapper around the new `findAppiumDependency()`. The strategy here is to use `npm list --long` to get detailed information about the current directory. The result will have an object with a `path` property, and that property points to the current workspace root (or current project root). We can then read the `package.json` in the `path` property--or just the CWD--to make the determination about an `appium` dependency (or lack thereof). For extension working copies, this will return `true` because `appium` will be present in `devDependencies`, `peerDependencies`, or both. For any other project, it will usually just be in `devDependencies`. If there's no `package.json` in the CWD and we're not in a workspace, Appium continues to use the default `APPIUM_HOME`.
One side effect of this is that running `appium` from the monorepo itself treats the dir hierarchy as a package which has an `appium` dependency (because it does!). To that end, the default `APPIUM_HOME` will _not_ be used when running `appium` from _anywhere in the monorepo_ unless you explicitly set `APPIUM_HOME` in an environment variable. Generally, our tests prescribe their own temporary `APPIUM_HOME` directories, so this should have no effect on them (in the general case). It _will_ have an effect on running `appium` manually in a development environment, as the workspace root will be treated as `APPIUM_HOME`; running `node ./packages/appium/index.js driver install uiautomator2` (or `npm start -- driver install uiautomator2`) will install that driver as a dev dependency (and save it). I could add a special case _just for the monorepo_ if we don't want this to happen, but it may introduce complexity we/I don't want to maintain, so I left it out. Furthermore, `npm start -- driver list` will show the `fake` driver, and `npm start -- plugin list` will show all of the plugins in `packages/`.
Regardless, I view this as a solid win for extension developers.
Bonus:
While I don't have benchmarks, this should considerably improve performance when detecting locally-installed (`node_modules/some-extension`) or extension working copies. Instead of using `klaw` to walk the filesystem (in serial!) we can just use `glob` to look for relevant `package.json` files. Instead of waiting until `glob` is completely finished searching, we can listen for its `match` evens and begin processing `package.json` files as soon as they are found. Because `@appium/support` only exposes a promisifed `glob()`--with no access to the `EventEmitter` it returns--`appium` depends on `glob` directly.
This is handy for drivers which need to find executables in the filesystem.
Also fixes possible false-positives in `fs.exists()`/`fs.hasAccess()` on Windows.
This package was missing `@appium/types`, which means packages consuming `@appium/support` which _don't_ also consume `appium` in some capacity will have types that won't compile, e.g., `teen_process`.
This can happen if someone does something like `npm install --no-save appium`, _or_ if npm changes its shrinkwrap behavior for reasons that cause `appium` to be installed in `$APPIUM_HOME/node_modules` _(cough)_
Ref: #17073
this change uses --legacy-peer-deps for newer versions of npm to
avoid installation of appium when installing extensions in ~/.appium. this does not work if the extension contains a shrinkwrap with appium in it, though.
in that case, an extra copy of appium will always be installed.
it creates a symlink, e.g., ~/.appium/node_modules/appium to the currently-running appium, wherever that is. could not abuse NODE_PATH to do this.
this is rather naive and does not check that the symlink is actually the same as the running appium if it already exists. that might cause some weird problems with multiple installs of appium on the same machine, but if it does, we can fix them as they arise.
When any package here is consumed as a library, the production deps installed alongside it _must_ also include depenencies related to type information. If these packages _aren't_ included, consumers will not have the requisite declarations installed and will get incomplete type information--at best--or worse; compilation errors.
Putting the onus on the consumer to install these requisite types is both user-hostile _and_ can result in the incorrect versions of type declarations being installed.
To that end, I've moved the various type declaration deps to production deps of the packages in which they are used. Sometimes this is multiple packages (in the case of, say, `@types/teen_process`). This results in many types being removed from the monorepo root. Those that remain are for _dev dependencies only_. If a packages uses, say, `ws`, but only in its tests, then the types can remain in the monorepo root along with the rest of the common dev deps.
I also saw an unused `supports-color` in `appium` and removed it.
This uses the [boneskull/nodejs-production-test-action](https://github.com/boneskull/nodejs-production-test-action) GH action to run a smoke test across all packages.
The action does the following:
1. Runs `npm pack` on each package, writing the tarball to a temp dir. This tarball contains the package as a user would `npm install` it.
2. Changes into the temp dir and runs `npm install <tarball>` on each
3. Runs a specified script (in our case, `test:smoke`) in each installed package's dir in `<tmp_dir>/node_modules`
Because `devDependencies` will not be present, this should avoid a class of issues where production deps are miscategorized as dev deps.
The action should probably use a separate temp dir for each--in the case of a dependency being present but only because some other package depends on it--but it's not smart enough to figure out peer dependencies yet.
This PR changes a few things:
- Extension problems are now displayed correctly at `appium server` startup. This was done by changing the default `npmlog` level, then reesetting it to `silent` when `winston` takes over (in `logsink.init()`)
- Extension problems are also displayed at install time.
- Improved performance of `appium <driver|plugin> install` in many cases by actually checking if the thing is installed _before_ installing it.
- `ExtensionCommand` uses a new console logging mechanism (`console` in `@appium/support`) tailored to CLI usage, since it is intended to be run via the CLI. Using this, we handle the result of extension checks both at server runtime and during CLI tool usage in the appropriate manner. The implementation is just a dumb wrapper around `console.log` and should eventually be removed when we revisit the logging architecture.
- Separated extension checks further into "errors" ("Problems") and "warnings". As these demand distinct log levels, `ExtensionConfig` no longer accepts a `logFn` in its constructor (since this restricted to a single level ("error"))
- Generally improved specificity, helpfulness, and reduced extraneous verbosity (like this sentence) of warnings
- Removed `strip-colors`, as this functionality is present in `@colors/colors`. The E2E test helper now automatically strips colors from child processes.
- More tests
- Change `e2e-helpers` to use `CliConsole` for command logging output during tests
- Change the "uninstall" command to use `npm uninstall`, since `rm -rf` will hose `node_modules` if the current project has a dependency on `appium` (in other words, if they are otherwise using a package manager to manage extensions). This is slower but safer.
Resolves#16924
Because the `postinstall` script of `appium` needs functions in `@appium/support`, that module must be compiled _before_ its `postinstall` script runs. Prior to this PR, only the monorepo root would run a `postinstall` script to build the subpackages. Now, each package has a `prepare` script which runs its own build; this happens prior to any `postinstall`. This way, the `postinstall` script in `appium` can run successfully.
- Some types in `appium` were renamed
- Others avoid errors
- Some are minor tweaks to `tsconfig.json` files
# Conflicts:
# packages/appium/lib/extension/extension-config.js
# packages/appium/types/extension-manifest.ts
# packages/appium/types/extension.ts
# packages/base-driver/lib/jsonwp-proxy/proxy.js
# packages/support/lib/logging.js
# packages/support/test/unit/logger/logger-force.spec.js