|
| 1 | + |
| 2 | +# Update Command |
| 3 | + |
| 4 | +`ng update` is a new command in the CLI to update one or multiple packages, its peer dependencies, and the peer dependencies that depends on it. |
| 5 | + |
| 6 | +If there are inconsistencies, for example if peer dependencies cannot be matches by a simple semver range, the tool will error out (and nothing will be committed on the filesystem). |
| 7 | + |
| 8 | +## Command Line Usage |
| 9 | + |
| 10 | +```bash |
| 11 | +ng update <package1 [package2 [...]]> [options] |
| 12 | +``` |
| 13 | +
|
| 14 | +You can specify more than one package. Each package follows the convention of `[@scope/]packageName[@version-range-or-dist-tag]`. Packages not found in your dependencies will trigger an error. Any package that has a higher version in your `package.json` will trigger an error. |
| 15 | +
|
| 16 | +| Flag | Argument | Description | |
| 17 | +|---|---|---| |
| 18 | +| `--all` | `boolean` | If true, implies that all dependencies should be updated. Defaults is false, using dependencies from the command line instead. | |
| 19 | +| `--next` | `boolean` | If true, allows version discovery to include Beta and RC. Defaults to false. | |
| 20 | +| `--migration-only` | `boolean` | If true, don't change the `package.json` file, only apply migration scripts. | |
| 21 | +| `--from` | `version` | Apply migrations from a certain version number. | |
| 22 | +| `--to` | `version` | Apply migrations up to a certain version number (inclusive). By default will update to the tag selected. | |
| 23 | +
|
| 24 | +## Details |
| 25 | +
|
| 26 | +The schematic performs the following steps, in order: |
| 27 | +
|
| 28 | +1. Get all installed package names and versions from the `package.json` into `dependencyMap: Map<string, string>`. |
| 29 | +1. From that map, fetch all `package.json` from the NPM repository, which contains all versions, and gather them in a `Map<string, NpmPackageJson>`. |
| 30 | + 1. At the same time, update the `Map<>` with the version of the package which is believed to be installed (largest version number matching the version range). |
| 31 | + 1. **WARNING**: this might not be the exact installed versions, unfortunately. We should have a proper `package-lock.json` loader, and support `yarn.lock` as well, but these are stretch goals (and where do we stop). |
| 32 | +1. For each packages mentioned on the command line, update to the target version (by default largest non-beta non-rc version): |
| 33 | +
|
| 34 | + ```python |
| 35 | + # ARGV The packages being requested by the user. |
| 36 | + # NPM A map of package name to a map of version to PackageJson structure. |
| 37 | + # V A map of package name to available versions. |
| 38 | + # PKG A map of package name to PackageJson structure, for the installed versions. |
| 39 | + # next A flag for the "--next" command line argument. |
| 40 | +
|
| 41 | + # First add all updating packages' peer dependencies. This should be recursive but simplified |
| 42 | + # here for readability. |
| 43 | + ARGV += [ NPM[p][max([ v for v in V[p] if (not is_beta(v) or next) ])].peerDependencies |
| 44 | + for p in ARGV ] |
| 45 | +
|
| 46 | + for p in ARGV: |
| 47 | + x = max([ v for v in V[p] if (not is_beta(v) or next) ]) |
| 48 | +
|
| 49 | + for other in set(PKG.keys()) - set([ p ]): |
| 50 | + # Verify all packages' peer dependencies. |
| 51 | + if has(other.peerDependencies, p) and !compatible(x, other.peerDependencies[p]): |
| 52 | + showError('Cannot update dependency "%s": "%s" is incompatible with the updated dependency' % (x, other)) |
| 53 | +
|
| 54 | + if any( has(other.peerDependencies, peer) and !compatible(x, other.peerDependencies[peer]) |
| 55 | + for peer in PKG[p].peerDependencies.keys() ): |
| 56 | + showError('Cannot update dependency "%s": "%s" depends on an incompatible peer dependency' % (x, other)) |
| 57 | +
|
| 58 | + update_package_json(p, x) |
| 59 | +``` |
| 60 | +
|
| 61 | +
|
| 62 | +
|
| 63 | +## Library Developers |
| 64 | +
|
| 65 | +Libraries are responsible for defining their own update schematics. The `ng update` tool will update the package.json, and if it detects am `"ng-update"` key in package.json of the library, will run the update schematic on it (with version information metadata). |
| 66 | +
|
| 67 | +If a library does not define the `"ng-update"` key in their package.json, they are considered not supporting the update workflow and `ng update` is basically equivalent to `npm install`. |
| 68 | +
|
| 69 | +### Migration |
| 70 | +
|
| 71 | +In order to implement migrations in a library, the author must add the `ng-update` key to its `package.json`. This key contains the following fields: |
| 72 | +
|
| 73 | +| Field Name | Type | Description | |
| 74 | +|---|---|---| |
| 75 | +| `requirements` | `{ [packageName: string]: VersionRange }` | A map of package names to version to check for minimal requirement. If one of the libraries listed here does not match the version range specified in `requirements`, an error will be shown to the user to manually update those libraries. For example, `@angular/core` does not support updates from versions earlier than 5, so this field would be `{ '@angular/core': '>= 5' }`. |
| 76 | +| `migrations` | `string` | A relative path (or resolved using Node module resolution) to a Schematics collection definition. | |
| 77 | +| `packageGroup` | `string[]` | A list of npm packages that are to be grouped together. When running |
| 78 | +
|
| 79 | +#### Example given: |
| 80 | +Library my-lib wants to have 2 steps to update from version 4 -> 4.5 and 4.5 to 5. It would add this information in its `package.json`: |
| 81 | +
|
| 82 | +```json |
| 83 | +{ |
| 84 | + "ng-update": { |
| 85 | + "requirements": { |
| 86 | + "my-lib": "^5" |
| 87 | + }, |
| 88 | + "migrations": "./migrations/migration-collection.json" |
| 89 | + } |
| 90 | +} |
| 91 | +``` |
| 92 | +
|
| 93 | +And create a migration collection (same schema as the Schematics collection): |
| 94 | +
|
| 95 | +```json |
| 96 | +{ |
| 97 | + "schematics": { |
| 98 | + "migration-01": { |
| 99 | + "version": "6", |
| 100 | + "factory": "./update-6" |
| 101 | + }, |
| 102 | + "migration-02": { |
| 103 | + "version": "6.2", |
| 104 | + "factory": "./update-6_2" |
| 105 | + }, |
| 106 | + "migration-03": { |
| 107 | + "version": "6.3", |
| 108 | + "factory": "./update-6_3" |
| 109 | + }, |
| 110 | + "migration-04": { |
| 111 | + "version": "7", |
| 112 | + "factory": "./update-7" |
| 113 | + }, |
| 114 | + "migration-05": { |
| 115 | + "version": "8", |
| 116 | + "factory": "./update-8" |
| 117 | + } |
| 118 | + } |
| 119 | +} |
| 120 | +``` |
| 121 | +
|
| 122 | +The update tool would then read the current version of library installed, check against all `version` fields and run the schematics, until it reaches the version required by the user (inclusively). If such a collection is used to update from version 5 to version 7, the `01`, `02`, `03,` and `04` functions would be called. If the current version is 7 and a `--refactor-only` flag is passed, it would run the migration `04` only. More arguments are needed to know from which version you are updating. |
| 123 | +
|
| 124 | +Running `ng update @angular/core` would be the same as `ng generate @angular/core/migrations:migration-01`. |
| 125 | +
|
| 126 | +## Use cases |
| 127 | +
|
| 128 | +### Help |
| 129 | +
|
| 130 | +`ng update`, shows what updates would be applied; |
| 131 | +
|
| 132 | +```sh |
| 133 | +$ ng update |
| 134 | +We analyzed your package.json, there's some packages to update: |
| 135 | +
|
| 136 | +Name Version Command to update |
| 137 | +---------------------------------------------------------------------------- |
| 138 | +@angular/cli 1.7.0 > 6.0.0 ng update @angular/cli |
| 139 | +@angular/core 5.4.3 > 6.0.1 ng update @angular/core |
| 140 | +@angular/material 5.2.1 > 6.0.0 ng update @angular/material |
| 141 | +@angular/router 5.4.3 > 6.0.1 ng update @angular/core |
| 142 | +
|
| 143 | +There might be additional packages that are outdated. |
| 144 | +``` |
| 145 | +
|
| 146 | +### Simple Multi-steps |
| 147 | +
|
| 148 | +I have a dependency on Angular, Material and CLI. I want to update the CLI, then Angular, then Material in separate steps. |
| 149 | +
|
| 150 | +#### Details |
| 151 | +1. `ng update @angular/cli`. |
| 152 | +Updates the CLI and packages that have a peer dependencies on the CLI (none), running refactoring tools from CLI 1 to 6. |
| 153 | +1. `ng update @angular/core`. |
| 154 | +Updates the Core package and all packages that have a peer dependency on it. This can get tricky if `@angular/material` get caught in the update because the version installed does not directly allow the new version of `@angular/core`. In this case |
| 155 | +
|
| 156 | +### Complex Case |
| 157 | +
|
| 158 | +package.json: |
| 159 | +
|
| 160 | +```json |
| 161 | +{ |
| 162 | + "dependencies": { |
| 163 | + "@angular/material": "5.0.0", |
| 164 | + "@angular/core": "5.5.5" |
| 165 | + } |
| 166 | +} |
| 167 | +``` |
| 168 | +
|
| 169 | +Commands: |
| 170 | +
|
| 171 | +```bash |
| 172 | +ng update @angular/core |
| 173 | +``` |
| 174 | +
|
| 175 | +- updates `@angular/core` to the `latest` dist-tag (6.0.0) |
| 176 | +- sees that `@angular/material` is not compatible with 6.0.0; **error out.** |
| 177 | +
|
| 178 | +```bash |
| 179 | +ng update @angular/material |
| 180 | +``` |
| 181 | +
|
| 182 | +- update `@angular/material` to latest version, that should be compatible with the current `@angular/core`. |
| 183 | +- if that version is not compatible with you |
| 184 | +- tell the user about a higher version that requires an update to `@angular/core`. |
| 185 | +
|
| 186 | +
|
| 187 | +## Notes |
| 188 | +
|
| 189 | +1. if someone is on CLI 1.5, the command is not supported. The user needs to update to `@angular/cli@latest`, then `ng update @angular/cli`. Post install hook will check versions of cli configuration and show a message to run the `ng update` command. |
| 190 | +1. NPM proxies or cache are not supported by the first version of this command. |
0 commit comments