Skip to content

Commit 9b7f439

Browse files
committedFeb 22, 2025
docs: add guide for migrating packages
--- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown status: passed - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: na - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed ---
1 parent b034c93 commit 9b7f439

File tree

1 file changed

+361
-0
lines changed

1 file changed

+361
-0
lines changed
 

‎docs/contributing/moving_packages.md

+361
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,361 @@
1+
<!--
2+
3+
@license Apache-2.0
4+
5+
Copyright (c) 2025 The Stdlib Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
19+
-->
20+
21+
# Package Migration
22+
23+
> This document is intended to provide a step-by-step guide for moving a package from one part of the codebase to another part of the codebase. This guide also applies when renaming a package.
24+
25+
The following outlines a sequence of steps to follow in order to migrate a single strided API package which is in `stats/base` to `stats/strided`.
26+
27+
At a high level, the process is as follows:
28+
29+
1. Copy the existing package to a new location.
30+
2. Update all import paths which point to the original package to the new copy.
31+
3. Remove the original package.
32+
33+
A more detailed sequence follows. It is **extremely important** to closely follow each step in order to avoid inadvertently breaking downstream packages within the project.
34+
35+
## Steps
36+
37+
### 0. Establish a clean working repository
38+
39+
You should avoid performing a migration on a repository branch which has unstaged changes. Your repository should be in a clean and pristine state prior to performing a package migration. Because you will often be making changes which are randomly spread out across the entire codebase, you want to avoid a scenario where you unintentionally commit changes unrelated to the migration.
40+
41+
Ensure that you create a new branch from the latest upstream `develop`. Assuming that your `upstream` is the main stdlib development repository (i.e., `https://github.com/stdlib-js/stdlib.git`),
42+
43+
```bash
44+
git checkout develop
45+
git pull upstream develop
46+
git checkout -b <branch_name>
47+
```
48+
49+
where `<branch_name>` is a placeholder for the name of a branch on which you'll perform the migration (e.g., `migrate-foo-bar`).
50+
51+
### 1. Copy package
52+
53+
Copy the existing package to the desired location. Assuming you are in the top-level root project directory,
54+
55+
```bash
56+
cp -R lib/node_modules/@stdlib/path/to/existing/package lib/node_modules/@stdlib/path/to/new/package
57+
```
58+
59+
For example,
60+
61+
```bash
62+
cp -R lib/node_modules/@stdlib/stats/base/dmax lib/node_modules/@stdlib/stats/strided/dmax
63+
```
64+
65+
### 2. Update package contents
66+
67+
Next, update the contents of the new package, which is likely to include the following:
68+
69+
- The package name (`package.json`, `lib/index.js`, `README.md`, and any other files which include the name of the original package.
70+
71+
- If a package contains `src` and `include` directories,
72+
73+
- update the directory tree according to the path of the new package (e.g., `include/stdlib/stats/base/dmax` would become `include/stdlib/stats/strided/dmax`).
74+
- update header guards within header files in the `include` directory (e.g., `STDLIB_STATS_BASE_DMAX` would become `STDLIB_STATS_STRIDED_DMAX`).
75+
76+
There may be other contents needing updating, so be sure to carefully inspect package contents.
77+
78+
### 3. Compile any native files
79+
80+
If a package contains a `src/addon.c` file, ensure that the package successfully compiles by running the following command
81+
82+
```bash
83+
make install-node-addons NODE_ADDONS_PATTERN="path/to/new/package"
84+
```
85+
86+
For example,
87+
88+
```bash
89+
make install-node-addons NODE_ADDONS_PATTERN="stats/strided/dmax"
90+
```
91+
92+
### 4. Run package unit tests and quality control commands
93+
94+
To ensure that the new package works as intended, run the package's unit tests and other quality control commands.
95+
96+
#### Unit tests
97+
98+
```bash
99+
make test TESTS_FILTER=".*/path/to/new/package/.*"
100+
```
101+
102+
For example,
103+
104+
```bash
105+
make test TESTS_FILTER=".*/stats/strided/dmax/.*"
106+
```
107+
108+
#### Examples
109+
110+
```bash
111+
make examples EXAMPLES_FILTER=".*/path/to/new/package/.*"
112+
```
113+
114+
For example,
115+
116+
```bash
117+
make examples EXAMPLES_FILTER=".*/stats/strided/dmax/.*"
118+
```
119+
120+
If a package contains C examples, compile and run the C examples.
121+
122+
```bash
123+
make examples-c EXAMPLES_FILTER=".*/path/to/new/package/.*"
124+
```
125+
126+
For example,
127+
128+
```bash
129+
make examples-c EXAMPLES_FILTER=".*/stats/strided/dmax/.*"
130+
```
131+
132+
#### Benchmarks
133+
134+
```bash
135+
make benchmark BENCHMARKS_FILTER=".*/path/to/new/package/.*"
136+
```
137+
138+
For example,
139+
140+
```bash
141+
make benchmark BENCHMARKS_FILTER=".*/stats/strided/dmax/.*"
142+
```
143+
144+
If a package contains C benchmarks, compile and run the C benchmarks.
145+
146+
```bash
147+
make benchmark-c BENCHMARKS_FILTER=".*/path/to/new/package/.*"
148+
```
149+
150+
For example,
151+
152+
```bash
153+
make benchmark-c BENCHMARKS_FILTER=".*/stats/strided/dmax/.*"
154+
```
155+
156+
### 5. Commit new package
157+
158+
Provided all tests pass and source files successfully compile, commit the new package to your migration branch.
159+
160+
```bash
161+
git add lib/node_modules/@stdlib/path/to/new/package && git commit
162+
```
163+
164+
For example,
165+
166+
```bash
167+
git add lib/node_modules/@stdlib/stats/strided/dmax && git commit
168+
```
169+
170+
When writing the commit message, you should include the name of the package being added and, if there is a public issue related to this particular package migration, include a Git trailer which references that issue.
171+
172+
For example,
173+
174+
```text
175+
feat: add `stats/strided/dmax`
176+
177+
Ref: https://github.com/stdlib-js/stdlib/issues/4797
178+
```
179+
180+
### 6. Remove the export of the original package from its parent namespace
181+
182+
Next, open the `lib/index.js` file found in the parent namespace of the original package (e.g., `lib/node_modules/@stdlib/stats/base/lib/index.js`.
183+
184+
If that file includes an exported symbol from the original package, remove it. For example,
185+
186+
```diff
187+
-
188+
- /**
189+
- * @name dmax
190+
- * @memberof ns
191+
- * @readonly
192+
- * @type {Function}
193+
- * @see {@link module:@stdlib/stats/base/dmax}
194+
- */
195+
- setReadOnly( ns, 'dmax', require( '@stdlib/stats/base/dmax' ) );
196+
```
197+
198+
### 7. Commit the changes to the parent namespace
199+
200+
If you removed an exported symbol from the parent namespace, commit those changes, making note that this is a breaking change.
201+
202+
```bash
203+
git add lib/node_modules/@stdlib/path/to/original/parent/namespace && git commit
204+
```
205+
206+
For example
207+
208+
```bash
209+
git add lib/node_modules/@stdlib/stats/base && git commit
210+
```
211+
212+
In your commit message, you should include a `BREAKING_CHANGE`, migration instructions, and a reference to any related public issues. For example,
213+
214+
```text
215+
remove: remove `dmax` from namespace
216+
217+
This commit removes the `dmax` symbol from the `stats/base`
218+
namespace due to a package migration.
219+
220+
BREAKING CHANGE: remove `dmax`
221+
222+
To migrate, users should access the same symbol via the
223+
`stats/strided` namespace.
224+
```
225+
226+
### 8. Update paths using a global find-and-replace
227+
228+
Next, perform a global find-and-replace to migrate all `require` (and `import`) paths which currently reference the original package to reference the new package.
229+
230+
For example, the following `require` statement
231+
232+
```text
233+
var dmax = require( 'stats/base/dmax' );
234+
```
235+
236+
should become
237+
238+
```text
239+
var dmax = require( 'stats/strided/dmax' );
240+
```
241+
242+
A couple of very important notes to keep in mind when performing a global find-and-replace.
243+
244+
- Be **very careful** to avoid erroneously updating the paths of packages whose names have a common prefix (e.g., `stats/base/dmaxabs`, `stats/base/dmaxsorted`, `stats/base/dmaxabssorted`). Those packages should **not** be inadvertently updated.
245+
- Additionally, ensure that, for packages having C implementations, if a package basename (e.g., `dmax`) has a hyphen, then downstream include paths also need to be updated. E.g., for package `stats/base/foo-bar` with include file `stats/base/foo_bar`, all downstream packages which include the previous header file need to be updated accordingly (e.g., `stats/strided/foo_bar`).
246+
247+
### 9. Avoid updating original package and error database
248+
249+
There are three packages where we do **not** want to update `require` paths.
250+
251+
- The original package. The original package should remain working and keeps its original paths.
252+
- The global error database. The global error database is an append-only log. We need to avoid invalidating any existing references.
253+
- The REPL databases. Given the high velocity of stdlib development, updating these databases will create merge conflicts, which do not need to be immediately resolved. We can avoid the hassle of needing to rectify these conflicts by deferring to stdlib's daily cron job which automatically maintains and updates these databases.
254+
255+
To dismiss any changes made to the above, run the following command
256+
257+
```bash
258+
git checkout -- ./lib/node_modules/@stdlib/path/to/original/package && git checkout -- ./lib/node_modules/@stdlib/error && git checkout -- ./lib/node_modules/@stdlib/repl && git status
259+
```
260+
261+
For example,
262+
263+
```bash
264+
git checkout -- ./lib/node_modules/@stdlib/stats/base/dmax && git checkout -- ./lib/node_modules/@stdlib/error && git checkout -- ./lib/node_modules/@stdlib/repl && git status
265+
```
266+
267+
After running the above, double-check the results of `git status` to check that the list of changed files matches expectation.
268+
269+
### 10. Commit changes
270+
271+
Now that you've cleaned up the path updates, commit the changes to your branch.
272+
273+
```bash
274+
git add . && git commit
275+
```
276+
277+
As updating paths should not affect the behavior of downstream packages, your commit message should be a `refactor`, and you should include a reference to any public issue related to the migration. For example,
278+
279+
```text
280+
refactor: update paths
281+
282+
Ref: https://github.com/stdlib-js/stdlib/issues/4797
283+
```
284+
285+
### 11. Remove original package
286+
287+
At this point, now that all downstream packages use the new package, we should be able to remove the original package from the project.
288+
289+
290+
```bash
291+
rm -rf lib/node_modules/@stdlib/path/to/original/package
292+
```
293+
294+
For example,
295+
296+
297+
```bash
298+
rm -rf lib/node_modules/@stdlib/stats/base/dmax
299+
```
300+
301+
### 12. Commit changes
302+
303+
Commit the changes to your branch.
304+
305+
```bash
306+
git add lib/node_modules/@stdlib/path/to/original/package && git commit
307+
```
308+
309+
For example,
310+
311+
```bash
312+
git add lib/node_modules/@stdlib/stats/base/dmax && git commit
313+
```
314+
315+
In your commit message, you should include a `BREAKING_CHANGE`, migration instructions, and a reference to any related public issues. For example,
316+
317+
```text
318+
remove: remove `stats/base/dmax`
319+
320+
This commit removes `@stdlib/stats/base/dmax` in favor of
321+
`@stdlib/stats/strided/dmax`.
322+
323+
BREAKING CHANGE: remove `stats/base/dmax`
324+
325+
To migrate, users should update their require/import paths to use
326+
`@stdlib/stats/strided/dmax` which provides the same API and implementation.
327+
328+
Ref: https://github.com/stdlib-js/stdlib/issues/4797
329+
```
330+
331+
### 13. Push changes to remote repository
332+
333+
At this point, you've completed a package migration. You should attempt to push your changes to your remote repository.
334+
335+
```bash
336+
git push origin <branch_name>
337+
```
338+
339+
where `<branch_name>` is the name of the branch on which you've been working.
340+
341+
If you made these changes on a fork, you should open a pull request against the `develop` branch on the main project [repository][stdlib-github].
342+
343+
* * *
344+
345+
## Notes
346+
347+
- Notice that every commit includes a `Ref:` link back to the RFC issue on the main project repository. This is useful for providing additional context regarding changes, especially those involving deprecations.
348+
- Provided you have properly setup your local repository (see the [contributing][stdlib-contributing] and [development][stdlib-development] guides), linting will be performed after every commit, and, prior to pushing changes to a remote repository, affected unit tests, examples, and benchmarks should automatically run. Depending on how widely used the original package was throughout stdlib, these quality control steps may take considerable time, and it is possible that unrelated lint errors may be flagged. If possible, address any failures, restage the changes, and attempt to commit or push again.
349+
- As mentioned above, be **very careful** when performing global find-and-replace. It can be easy to mistakenly update non-applicable paths, thus breaking packages and all downstream dependents. You've been warned.
350+
351+
<section class="links">
352+
353+
[stdlib-github]: https://github.com/stdlib-js/stdlib
354+
355+
[stdlib-contributing]: https://github.com/stdlib-js/stdlib/blob/develop/CONTRIBUTING.md
356+
357+
[stdlib-development]: https://github.com/stdlib-js/stdlib/blob/develop/docs/contributing/development.md
358+
359+
</section>
360+
361+
<!-- /.links -->

0 commit comments

Comments
 (0)
Failed to load comments.