|
| 1 | +# Contributing |
| 2 | + |
| 3 | +Welcome to the Nushell standard library and thank you for considering contributing! |
| 4 | + |
| 5 | +## Ideas for the standard library |
| 6 | + |
| 7 | +If you've got a great idea, or just want to contribute to open source |
| 8 | +by working on the Nushell standard library, |
| 9 | +we invite you to talk to the team before you start coding. |
| 10 | +You'll find we're friendly, passionate about Nushell and always open to new ideas! |
| 11 | + |
| 12 | +You'll generally find the team members on |
| 13 | +[Discord standard-library channel](https://discord.com/channels/601130461678272522/1075541668922658868), |
| 14 | +and can have preliminary discussions there to clarify the issues involved. |
| 15 | + |
| 16 | +You can open a [Github issue](https://github.com/nushell/nushell/issues/new/choose) |
| 17 | +to have a more focused discussion of your idea. |
| 18 | + |
| 19 | +Generally, we think the standard library should contain items that are |
| 20 | +relevant to most/all Nushell users regardless of the application space they're working in. |
| 21 | +If your idea isn't quite so broadly applicable, |
| 22 | +consider publishing it in [nu_scripts](https://github.com/nushell/nu_scripts). |
| 23 | + |
| 24 | +Preliminary discussions should focus on the *user benefit* your idea would provide. |
| 25 | +How many users will be affected by your idea, how much would it help them solve a problem or work more productively? |
| 26 | +Given consensus on the user benefit, the team will be motivated to |
| 27 | +help you create, deploy and maintain a solution long term. |
| 28 | + |
| 29 | +## Lifecycle of a change |
| 30 | + |
| 31 | +1. Verify the team thinks your idea is potentially relevant and useful, as above. |
| 32 | +1. If it's more than a simple bug fix, open a placeholder PR |
| 33 | +as soon as you get started and [set it to draft status][github_draft_pr]. |
| 34 | +This will alert other contributors that you're working in this area and let you |
| 35 | +advertise roughly what scope of changes you're thinking of. |
| 36 | +See [below](#the_pr) for details. |
| 37 | +1. Get things working in your local development environment. |
| 38 | +If you have questions along the way, you can post a question in your PR |
| 39 | +or have a more casual discussion with Nushell fans on |
| 40 | +[Discord implementation-chat channel](https://discord.com/channels/601130461678272522/615962413203718156) |
| 41 | +1. When you get to an appropriate state of doneness, push your changes to the PR and remove the draft status. |
| 42 | +2. Team members and other contributors will then review your PR. |
| 43 | +Respond to any review comments they raise and address them one way or another. |
| 44 | +(Not all comments demand you make a change!) |
| 45 | +1. When you and the team are comfortable with the PR, |
| 46 | +a team member will merge it into the repo and you can delete your working branch. |
| 47 | +2. If you've added a whole new command or made a breaking change, |
| 48 | +(strongly) consider writing it up for the release notes. |
| 49 | +Currently, release notes are maintained in a different repo, [nushell.github.io](https://github.com/nushell/nushell.github.io). |
| 50 | +Make your change in a local clone of that repo and submit a PR to the release notes repo to get it integrated. |
| 51 | + |
| 52 | +## Developing |
| 53 | +(All paths below shown relative to the root folder of the git repository containing the standard library.) |
| 54 | +### Setup |
| 55 | + |
| 56 | +0. Install the Rust toolchain and Nushell build tools. See [nushell CONTRIBUTING](https://github.com/nushell/nushell/blob/main/CONTRIBUTING.md) for details. |
| 57 | +The standard library is tightly coupled to a particular version of Nushell interpreter, |
| 58 | +you need to be running that version to test your changes |
| 59 | +(unlike a "normal" script module library). |
| 60 | + |
| 61 | +1. Clone the Nushell repo containing the standard library and create a feature branch for your development work. |
| 62 | +Currently, that's the [Nushell interpreter source repo](https://github.com/nushell/nushell). |
| 63 | +Once you set your working directory to the root of this repository, you'll generally leave it there throughout the session. |
| 64 | + ``` |
| 65 | + git clone https://github.com/nushell/nushell |
| 66 | + cd nushell |
| 67 | + git checkout -b <featureBranch> |
| 68 | + ``` |
| 69 | +1. In your IDE, open the folder within the repository containing the standard library. |
| 70 | +The folder is currently `./crates/nu-std`, and it is a Rust crate, containing a `Cargo.toml` |
| 71 | +and subfolders: |
| 72 | +* `src/` (which contains the Rust code to load the standard library modules into memory for efficiency), |
| 73 | +* `lib` (which contains all the script module sources for the standard library), |
| 74 | +* `tests/` (unit tests for lib). |
| 75 | +### The PR |
| 76 | +Assuming you've already validated the need with other Nushell contributors, you're focusing on design and implementation |
| 77 | +at this point. Share your thinking all along the way! |
| 78 | + |
| 79 | +You can open a [draft][github_draft_pr] pull request based on a small, placeholder code change |
| 80 | +and use the PR comments to outline your design and user interface. You'll get feedback from |
| 81 | +other contributors that may lead to a more robust and perhaps more idomatic solution. |
| 82 | +The threads in the PR can be a convenient reference for you when writing release notes and |
| 83 | +for others on the team when researching issues. |
| 84 | + |
| 85 | +Note that the PR will not get final code review or be merged until you remove the draft status. |
| 86 | +### Design considerations |
| 87 | +The standard library consists of Nushell custom commands and their associated environment variables, packaged in script modules underneath module `std`. For background on scripts, custom commands and modules, see |
| 88 | +[Modules chapter of the Nushell book](https://www.nushell.sh/book/modules.html). |
| 89 | + |
| 90 | +To add a completely new module, for example, a `foo` command and some `foo subcommand`s, |
| 91 | +you will be dealing with 2 new source files: the module source itself (`./crates/nu-std/lib/foo.nu`) and a unit tests file (`./crates/nu-std/tests/test_foo`); and will be modifying 1 or 2 existing files (`./crates/nu-std/lib/mod.nu` and possibly `./crates/nu-std/src/lib.rs`). This is described below: |
| 92 | + |
| 93 | +1. Source for a custom command `foo` should go in `./crates/nu-std/lib/foo.nu`. |
| 94 | + |
| 95 | + * A source file will typically implement multiple subcommands and possibly a main command as well. |
| 96 | + Use `export def` to make these names public to your users. |
| 97 | + * If your command is updating environment variables, you must use `export def-env` (instead of `export def`) |
| 98 | + to define the subcommand, `export-env {}` to initialize the environment variables and `let-env` to update them. |
| 99 | + For an example of a custom command which modifies environment variables, |
| 100 | + see: `./crates/nu-std/lib/dirs.nu`. |
| 101 | + For an example of a custom command which does *not* modify environment variables, see: `./crates/nu-std/lib/assert.nu`. |
| 102 | + * If your standard library module wishes to use a utility from another module of the standard library, |
| 103 | + for example `log info`, |
| 104 | + you need to import it directly from its module in the `use` statement. |
| 105 | + ```shell |
| 106 | + ... your foo.nu ... |
| 107 | + export def mycommand [] { |
| 108 | + use log "log info" |
| 109 | + . . . |
| 110 | + log info "info level log message" |
| 111 | + . . . |
| 112 | + } |
| 113 | + ``` |
| 114 | + This is `use log "log info"` rather than `use std "log info"` (which is the usual way commands are imported |
| 115 | + from the standard library) because your `foo` module is also a child module under `std`. |
| 116 | + |
| 117 | +1. Unit tests for `foo` should go in `./crates/nu-std/tests/test_foo.nu`. Thou shalt provide unit tests to cover your changes. |
| 118 | + * Unit tests should use one of the `assert` commands to check a condition and report the failure in a standard format. |
| 119 | + * To import `assert` commands for use in your test, import them via `use std` (unlike the `use log` for your source code; the tests are not modules under `std`). For example: |
| 120 | + ```shell |
| 121 | + ... your test_foo.nu ... |
| 122 | + def test1 [] { |
| 123 | + use std |
| 124 | + . . . |
| 125 | + std assert greater $l $r |
| 126 | + . . . |
| 127 | + std assert $predicate |
| 128 | + } |
| 129 | + |
| 130 | + def test2 [] { |
| 131 | + use std ['assert greater' assert] |
| 132 | + . . . |
| 133 | + assert greater $l $r |
| 134 | + . . . |
| 135 | + assert $predicate |
| 136 | + } |
| 137 | + ``` |
| 138 | + The choice of import style is up to you. |
| 139 | + |
| 140 | + |
| 141 | +2. A `foo` command will be exposed to the user as `std foo` (at a minimum). |
| 142 | +To enable this, update file `./crates/nu-std/lib/mod.nu` and add this code: |
| 143 | + ``` |
| 144 | + export use foo * # command doesn't update environment |
| 145 | + export-env { |
| 146 | + use bar * # command *does* update environment |
| 147 | + } |
| 148 | + ``` |
| 149 | + The `use *` hoists the public definitions in `foo.nu` into `mod.nu` and thus into the `std` namespace. |
| 150 | +
|
| 151 | +1. Some commands from the standard library are also preloaded, so user can invoke them without explicit |
| 152 | +import via `use std ...`. |
| 153 | +A command implemented as `std foo`, can be preloaded as a bare `foo`: |
| 154 | + * modify `./crates/nu-std/src/lib.rs`, |
| 155 | + * find the initialization of the "prelude" at line 90 or thereabouts |
| 156 | + * add `("foo", "foo")` |
| 157 | + * or, to be preloaded as `std foo`, add `("std foo", "foo")`. |
| 158 | + |
| 159 | + (This code may be restructured soon: if you can't find it, check with the team on Discord.) |
| 160 | +Note that you will need to recompile the Nushell interpreter to test this change, |
| 161 | +see [Nushell CONTRIBUTING#Setup](https://github.com/nushell/nushell/blob/main/CONTRIBUTING.md#setup). |
| 162 | +
|
| 163 | +More design guidelines: |
| 164 | +
|
| 165 | +1. Ensure your custom command provides useful help. |
| 166 | +This is done with comments before the `def` for the custom command. |
| 167 | +1. Use `error make` to report can't-proceed errors to user, not `log error`. |
| 168 | +2. Use `log info` to provide verbose progress messages that the user can optionally enable for troubleshooting. |
| 169 | +e.g: |
| 170 | + ```shell |
| 171 | + NU_LOG_LEVEL=INFO foo # verbose messages from command foo |
| 172 | + ``` |
| 173 | +1. Use `assert` in unit tests to check for and report failures. |
| 174 | +
|
| 175 | +### Useful Commands |
| 176 | +
|
| 177 | +- Run all unit tests for the standard library: |
| 178 | + |
| 179 | + ```shell |
| 180 | + cargo run -- -c 'use std; NU_LOG_LEVEL=ERROR std run-tests' |
| 181 | +
|
| 182 | + ``` |
| 183 | + Note that this uses the debug version of NU interpreter from the same repo, which is the usual development scenario. |
| 184 | + Log level 'ERROR' shows only failures (meaning no output is the desired outcome). |
| 185 | + Log level 'INFO' shows progress by module and 'DEBUG' show each individual test. |
| 186 | + |
| 187 | +- Run all tests for a specific test module, e.g, `crates/nu-std/tests/test_foo.nu` |
| 188 | + |
| 189 | + ```shell |
| 190 | + cargo run -- -c 'use std; NU_LOG_LEVEL=INFO std run-tests --module test_foo' |
| 191 | + ``` |
| 192 | + |
| 193 | +- Run a custom command with additional logging (assuming you have instrumented |
| 194 | +the command with `log <level>`, as we recommend.) |
| 195 | + |
| 196 | + ```shell |
| 197 | + NU_LOG_LEVEL=INFO std foo bar bas # verbose |
| 198 | + NU_LOG_LEVEL=DEBUG std foo bar bas # very verbose |
| 199 | + ``` |
| 200 | +- Build and run Nushell (e.g, if you modify the prelude): |
| 201 | + |
| 202 | + ```shell |
| 203 | + cargo run |
| 204 | + ``` |
| 205 | +## Git commit and repo conventions |
| 206 | +The standard library project uses the same protocols and conventions |
| 207 | +for squashing git commits and handling github PRs as the core Nushell project. |
| 208 | +Please see [nushell CONTRIBUTING#git_etiquette](https://github.com/nushell/nushell/blob/main/CONTRIBUTING.md#git-etiquette) for details. |
| 209 | + |
| 210 | +[github_draft_pr]:(https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request) |
0 commit comments