]>
Commit | Line | Data |
---|---|---|
13cf67c4 XL |
1 | ## Publishing a Crate to Crates.io |
2 | ||
dc9dc135 | 3 | We’ve used packages from [crates.io](https://crates.io/)<!-- ignore --> as |
13cf67c4 XL |
4 | dependencies of our project, but you can also share your code with other people |
5 | by publishing your own packages. The crate registry at | |
dc9dc135 | 6 | [crates.io](https://crates.io/)<!-- ignore --> distributes the source code of |
13cf67c4 XL |
7 | your packages, so it primarily hosts code that is open source. |
8 | ||
04454e1e FG |
9 | Rust and Cargo have features that make your published package easier for people |
10 | to find and use. We’ll talk about some of these features next and then explain | |
11 | how to publish a package. | |
13cf67c4 XL |
12 | |
13 | ### Making Useful Documentation Comments | |
14 | ||
15 | Accurately documenting your packages will help other users know how and when to | |
16 | use them, so it’s worth investing the time to write documentation. In Chapter | |
17 | 3, we discussed how to comment Rust code using two slashes, `//`. Rust also has | |
18 | a particular kind of comment for documentation, known conveniently as a | |
19 | *documentation comment*, that will generate HTML documentation. The HTML | |
20 | displays the contents of documentation comments for public API items intended | |
21 | for programmers interested in knowing how to *use* your crate as opposed to how | |
22 | your crate is *implemented*. | |
23 | ||
24 | Documentation comments use three slashes, `///`, instead of two and support | |
25 | Markdown notation for formatting the text. Place documentation comments just | |
26 | before the item they’re documenting. Listing 14-1 shows documentation comments | |
5099ac24 | 27 | for an `add_one` function in a crate named `my_crate`. |
13cf67c4 XL |
28 | |
29 | <span class="filename">Filename: src/lib.rs</span> | |
30 | ||
31 | ```rust,ignore | |
74b04a01 | 32 | {{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-01/src/lib.rs}} |
13cf67c4 XL |
33 | ``` |
34 | ||
35 | <span class="caption">Listing 14-1: A documentation comment for a | |
36 | function</span> | |
37 | ||
38 | Here, we give a description of what the `add_one` function does, start a | |
39 | section with the heading `Examples`, and then provide code that demonstrates | |
40 | how to use the `add_one` function. We can generate the HTML documentation from | |
41 | this documentation comment by running `cargo doc`. This command runs the | |
42 | `rustdoc` tool distributed with Rust and puts the generated HTML documentation | |
43 | in the *target/doc* directory. | |
44 | ||
45 | For convenience, running `cargo doc --open` will build the HTML for your | |
46 | current crate’s documentation (as well as the documentation for all of your | |
47 | crate’s dependencies) and open the result in a web browser. Navigate to the | |
48 | `add_one` function and you’ll see how the text in the documentation comments is | |
49 | rendered, as shown in Figure 14-1: | |
50 | ||
51 | <img alt="Rendered HTML documentation for the `add_one` function of `my_crate`" src="img/trpl14-01.png" class="center" /> | |
52 | ||
53 | <span class="caption">Figure 14-1: HTML documentation for the `add_one` | |
54 | function</span> | |
55 | ||
56 | #### Commonly Used Sections | |
57 | ||
58 | We used the `# Examples` Markdown heading in Listing 14-1 to create a section | |
59 | in the HTML with the title “Examples.” Here are some other sections that crate | |
60 | authors commonly use in their documentation: | |
61 | ||
62 | * **Panics**: The scenarios in which the function being documented could | |
63 | panic. Callers of the function who don’t want their programs to panic should | |
64 | make sure they don’t call the function in these situations. | |
65 | * **Errors**: If the function returns a `Result`, describing the kinds of | |
66 | errors that might occur and what conditions might cause those errors to be | |
67 | returned can be helpful to callers so they can write code to handle the | |
68 | different kinds of errors in different ways. | |
69 | * **Safety**: If the function is `unsafe` to call (we discuss unsafety in | |
70 | Chapter 19), there should be a section explaining why the function is unsafe | |
71 | and covering the invariants that the function expects callers to uphold. | |
72 | ||
73 | Most documentation comments don’t need all of these sections, but this is a | |
04454e1e FG |
74 | good checklist to remind you of the aspects of your code users will be |
75 | interested in knowing about. | |
13cf67c4 XL |
76 | |
77 | #### Documentation Comments as Tests | |
78 | ||
79 | Adding example code blocks in your documentation comments can help demonstrate | |
80 | how to use your library, and doing so has an additional bonus: running `cargo | |
81 | test` will run the code examples in your documentation as tests! Nothing is | |
82 | better than documentation with examples. But nothing is worse than examples | |
83 | that don’t work because the code has changed since the documentation was | |
84 | written. If we run `cargo test` with the documentation for the `add_one` | |
85 | function from Listing 14-1, we will see a section in the test results like this: | |
86 | ||
74b04a01 XL |
87 | <!-- manual-regeneration |
88 | cd listings/ch14-more-about-cargo/listing-14-01/ | |
89 | cargo test | |
90 | copy just the doc-tests section below | |
91 | --> | |
92 | ||
13cf67c4 XL |
93 | ```text |
94 | Doc-tests my_crate | |
95 | ||
96 | running 1 test | |
97 | test src/lib.rs - add_one (line 5) ... ok | |
98 | ||
6a06907d | 99 | test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s |
13cf67c4 XL |
100 | ``` |
101 | ||
102 | Now if we change either the function or the example so the `assert_eq!` in the | |
103 | example panics and run `cargo test` again, we’ll see that the doc tests catch | |
104 | that the example and the code are out of sync with each other! | |
105 | ||
106 | #### Commenting Contained Items | |
107 | ||
04454e1e FG |
108 | The style of doc comment `//!` adds documentation to the item that contains the |
109 | comments rather than to the items following the comments. We typically use | |
110 | these doc comments inside the crate root file (*src/lib.rs* by convention) or | |
111 | inside a module to document the crate or the module as a whole. | |
13cf67c4 | 112 | |
04454e1e FG |
113 | For example, to add documentation that describes the purpose of the `my_crate` |
114 | crate that contains the `add_one` function, we add documentation comments that | |
115 | start with `//!` to the beginning of the *src/lib.rs* file, as shown in Listing | |
116 | 14-2: | |
13cf67c4 XL |
117 | |
118 | <span class="filename">Filename: src/lib.rs</span> | |
119 | ||
120 | ```rust,ignore | |
74b04a01 | 121 | {{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-02/src/lib.rs:here}} |
13cf67c4 XL |
122 | ``` |
123 | ||
124 | <span class="caption">Listing 14-2: Documentation for the `my_crate` crate as a | |
125 | whole</span> | |
126 | ||
127 | Notice there isn’t any code after the last line that begins with `//!`. Because | |
128 | we started the comments with `//!` instead of `///`, we’re documenting the item | |
129 | that contains this comment rather than an item that follows this comment. In | |
04454e1e FG |
130 | this case, that item is the *src/lib.rs* file, which is the crate root. These |
131 | comments describe the entire crate. | |
13cf67c4 XL |
132 | |
133 | When we run `cargo doc --open`, these comments will display on the front | |
134 | page of the documentation for `my_crate` above the list of public items in the | |
135 | crate, as shown in Figure 14-2: | |
136 | ||
137 | <img alt="Rendered HTML documentation with a comment for the crate as a whole" src="img/trpl14-02.png" class="center" /> | |
138 | ||
139 | <span class="caption">Figure 14-2: Rendered documentation for `my_crate`, | |
140 | including the comment describing the crate as a whole</span> | |
141 | ||
142 | Documentation comments within items are useful for describing crates and | |
143 | modules especially. Use them to explain the overall purpose of the container to | |
144 | help your users understand the crate’s organization. | |
145 | ||
146 | ### Exporting a Convenient Public API with `pub use` | |
147 | ||
13cf67c4 XL |
148 | The structure of your public API is a major consideration when publishing a |
149 | crate. People who use your crate are less familiar with the structure than you | |
150 | are and might have difficulty finding the pieces they want to use if your crate | |
151 | has a large module hierarchy. | |
152 | ||
04454e1e FG |
153 | In Chapter 7, we covered how to make items public using the `pub` keyword, and |
154 | bring items into a scope with the `use` keyword. However, the structure that | |
155 | makes sense to you while you’re developing a crate might not be very convenient | |
156 | for your users. You might want to organize your structs in a hierarchy | |
157 | containing multiple levels, but then people who want to use a type you’ve | |
158 | defined deep in the hierarchy might have trouble finding out that type exists. | |
159 | They might also be annoyed at having to enter `use` | |
160 | `my_crate::some_module::another_module::UsefulType;` rather than `use` | |
161 | `my_crate::UsefulType;`. | |
162 | ||
13cf67c4 XL |
163 | The good news is that if the structure *isn’t* convenient for others to use |
164 | from another library, you don’t have to rearrange your internal organization: | |
165 | instead, you can re-export items to make a public structure that’s different | |
166 | from your private structure by using `pub use`. Re-exporting takes a public | |
167 | item in one location and makes it public in another location, as if it were | |
168 | defined in the other location instead. | |
169 | ||
170 | For example, say we made a library named `art` for modeling artistic concepts. | |
171 | Within this library are two modules: a `kinds` module containing two enums | |
172 | named `PrimaryColor` and `SecondaryColor` and a `utils` module containing a | |
173 | function named `mix`, as shown in Listing 14-3: | |
174 | ||
175 | <span class="filename">Filename: src/lib.rs</span> | |
176 | ||
fc512014 | 177 | ```rust,noplayground,test_harness |
136023e0 | 178 | {{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-03/src/lib.rs:here}} |
13cf67c4 XL |
179 | ``` |
180 | ||
181 | <span class="caption">Listing 14-3: An `art` library with items organized into | |
182 | `kinds` and `utils` modules</span> | |
183 | ||
184 | Figure 14-3 shows what the front page of the documentation for this crate | |
185 | generated by `cargo doc` would look like: | |
186 | ||
187 | <img alt="Rendered documentation for the `art` crate that lists the `kinds` and `utils` modules" src="img/trpl14-03.png" class="center" /> | |
188 | ||
189 | <span class="caption">Figure 14-3: Front page of the documentation for `art` | |
190 | that lists the `kinds` and `utils` modules</span> | |
191 | ||
192 | Note that the `PrimaryColor` and `SecondaryColor` types aren’t listed on the | |
193 | front page, nor is the `mix` function. We have to click `kinds` and `utils` to | |
194 | see them. | |
195 | ||
196 | Another crate that depends on this library would need `use` statements that | |
197 | bring the items from `art` into scope, specifying the module structure that’s | |
198 | currently defined. Listing 14-4 shows an example of a crate that uses the | |
199 | `PrimaryColor` and `mix` items from the `art` crate: | |
200 | ||
201 | <span class="filename">Filename: src/main.rs</span> | |
202 | ||
203 | ```rust,ignore | |
74b04a01 | 204 | {{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-04/src/main.rs}} |
13cf67c4 XL |
205 | ``` |
206 | ||
207 | <span class="caption">Listing 14-4: A crate using the `art` crate’s items with | |
208 | its internal structure exported</span> | |
209 | ||
210 | The author of the code in Listing 14-4, which uses the `art` crate, had to | |
211 | figure out that `PrimaryColor` is in the `kinds` module and `mix` is in the | |
212 | `utils` module. The module structure of the `art` crate is more relevant to | |
04454e1e FG |
213 | developers working on the `art` crate than to those using it. The internal |
214 | structure doesn’t contain any useful information for someone trying to | |
215 | understand how to use the `art` crate, but rather causes confusion because | |
216 | developers who use it have to figure out where to look, and must specify the | |
217 | module names in the `use` statements. | |
13cf67c4 XL |
218 | |
219 | To remove the internal organization from the public API, we can modify the | |
220 | `art` crate code in Listing 14-3 to add `pub use` statements to re-export the | |
221 | items at the top level, as shown in Listing 14-5: | |
222 | ||
223 | <span class="filename">Filename: src/lib.rs</span> | |
224 | ||
225 | ```rust,ignore | |
74b04a01 | 226 | {{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-05/src/lib.rs:here}} |
13cf67c4 XL |
227 | ``` |
228 | ||
229 | <span class="caption">Listing 14-5: Adding `pub use` statements to re-export | |
230 | items</span> | |
231 | ||
232 | The API documentation that `cargo doc` generates for this crate will now list | |
233 | and link re-exports on the front page, as shown in Figure 14-4, making the | |
234 | `PrimaryColor` and `SecondaryColor` types and the `mix` function easier to find. | |
235 | ||
236 | <img alt="Rendered documentation for the `art` crate with the re-exports on the front page" src="img/trpl14-04.png" class="center" /> | |
237 | ||
238 | <span class="caption">Figure 14-4: The front page of the documentation for `art` | |
239 | that lists the re-exports</span> | |
240 | ||
241 | The `art` crate users can still see and use the internal structure from Listing | |
242 | 14-3 as demonstrated in Listing 14-4, or they can use the more convenient | |
243 | structure in Listing 14-5, as shown in Listing 14-6: | |
244 | ||
245 | <span class="filename">Filename: src/main.rs</span> | |
246 | ||
247 | ```rust,ignore | |
74b04a01 | 248 | {{#rustdoc_include ../listings/ch14-more-about-cargo/listing-14-06/src/main.rs:here}} |
13cf67c4 XL |
249 | ``` |
250 | ||
251 | <span class="caption">Listing 14-6: A program using the re-exported items from | |
252 | the `art` crate</span> | |
253 | ||
254 | In cases where there are many nested modules, re-exporting the types at the top | |
255 | level with `pub use` can make a significant difference in the experience of | |
923072b8 FG |
256 | people who use the crate. Another common use of `pub use` is to re-export |
257 | definitions of a dependency in the current crate to make that crate's | |
258 | definitions part of your crate’s public API. | |
13cf67c4 XL |
259 | |
260 | Creating a useful public API structure is more of an art than a science, and | |
261 | you can iterate to find the API that works best for your users. Choosing `pub | |
262 | use` gives you flexibility in how you structure your crate internally and | |
263 | decouples that internal structure from what you present to your users. Look at | |
264 | some of the code of crates you’ve installed to see if their internal structure | |
265 | differs from their public API. | |
266 | ||
267 | ### Setting Up a Crates.io Account | |
268 | ||
269 | Before you can publish any crates, you need to create an account on | |
dc9dc135 | 270 | [crates.io](https://crates.io/)<!-- ignore --> and get an API token. To do so, |
04454e1e FG |
271 | visit the home page at [crates.io](https://crates.io/)<!-- ignore --> and log |
272 | in via a GitHub account. (The GitHub account is currently a requirement, but | |
273 | the site might support other ways of creating an account in the future.) Once | |
13cf67c4 XL |
274 | you’re logged in, visit your account settings at |
275 | [https://crates.io/me/](https://crates.io/me/)<!-- ignore --> and retrieve your | |
276 | API key. Then run the `cargo login` command with your API key, like this: | |
277 | ||
f035d41b | 278 | ```console |
13cf67c4 XL |
279 | $ cargo login abcdefghijklmnopqrstuvwxyz012345 |
280 | ``` | |
281 | ||
282 | This command will inform Cargo of your API token and store it locally in | |
283 | *~/.cargo/credentials*. Note that this token is a *secret*: do not share it | |
284 | with anyone else. If you do share it with anyone for any reason, you should | |
dc9dc135 | 285 | revoke it and generate a new token on [crates.io](https://crates.io/)<!-- ignore |
13cf67c4 XL |
286 | -->. |
287 | ||
288 | ### Adding Metadata to a New Crate | |
289 | ||
04454e1e FG |
290 | Let’s say you have a crate you want to publish. Before publishing, you’ll need |
291 | to add some metadata in the `[package]` section of the crate’s *Cargo.toml* | |
292 | file. | |
13cf67c4 XL |
293 | |
294 | Your crate will need a unique name. While you’re working on a crate locally, | |
295 | you can name a crate whatever you’d like. However, crate names on | |
dc9dc135 | 296 | [crates.io](https://crates.io/)<!-- ignore --> are allocated on a first-come, |
13cf67c4 | 297 | first-served basis. Once a crate name is taken, no one else can publish a crate |
9fa01778 | 298 | with that name. Before attempting to publish a crate, search for the name you |
04454e1e FG |
299 | want to use. If the name has been used, you will need to find another name and |
300 | edit the `name` field in the *Cargo.toml* file under the `[package]` section to | |
301 | use the new name for publishing, like so: | |
13cf67c4 XL |
302 | |
303 | <span class="filename">Filename: Cargo.toml</span> | |
304 | ||
305 | ```toml | |
306 | [package] | |
307 | name = "guessing_game" | |
308 | ``` | |
309 | ||
310 | Even if you’ve chosen a unique name, when you run `cargo publish` to publish | |
311 | the crate at this point, you’ll get a warning and then an error: | |
312 | ||
74b04a01 XL |
313 | <!-- manual-regeneration |
314 | cd listings/ch14-more-about-cargo/listing-14-01/ | |
315 | cargo publish | |
316 | copy just the relevant lines below | |
317 | --> | |
318 | ||
f035d41b | 319 | ```console |
13cf67c4 | 320 | $ cargo publish |
74b04a01 XL |
321 | Updating crates.io index |
322 | warning: manifest has no description, license, license-file, documentation, homepage or repository. | |
323 | See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. | |
13cf67c4 | 324 | --snip-- |
5099ac24 FG |
325 | error: failed to publish to registry at https://crates.io |
326 | ||
327 | Caused by: | |
328 | the remote server responded with an error: missing or empty metadata fields: description, license. Please see https://doc.rust-lang.org/cargo/reference/manifest.html for how to upload metadata | |
13cf67c4 XL |
329 | ``` |
330 | ||
04454e1e | 331 | This errors because you’re missing some crucial information: a description and |
13cf67c4 | 332 | license are required so people will know what your crate does and under what |
04454e1e FG |
333 | terms they can use it. In *Cargo.toml*, add a description that's just a |
334 | sentence or two, because it will appear with your crate in search results. For | |
335 | the `license` field, you need to give a *license identifier value*. The [Linux | |
336 | Foundation’s Software Package Data Exchange (SPDX)][spdx] lists the identifiers | |
337 | you can use for this value. For example, to specify that you’ve licensed your | |
338 | crate using the MIT License, add the `MIT` identifier: | |
13cf67c4 XL |
339 | |
340 | <span class="filename">Filename: Cargo.toml</span> | |
341 | ||
342 | ```toml | |
343 | [package] | |
344 | name = "guessing_game" | |
345 | license = "MIT" | |
346 | ``` | |
347 | ||
348 | If you want to use a license that doesn’t appear in the SPDX, you need to place | |
349 | the text of that license in a file, include the file in your project, and then | |
350 | use `license-file` to specify the name of that file instead of using the | |
351 | `license` key. | |
352 | ||
353 | Guidance on which license is appropriate for your project is beyond the scope | |
354 | of this book. Many people in the Rust community license their projects in the | |
355 | same way as Rust by using a dual license of `MIT OR Apache-2.0`. This practice | |
356 | demonstrates that you can also specify multiple license identifiers separated | |
357 | by `OR` to have multiple licenses for your project. | |
358 | ||
136023e0 | 359 | With a unique name, the version, your description, and a license added, the |
13cf67c4 XL |
360 | *Cargo.toml* file for a project that is ready to publish might look like this: |
361 | ||
362 | <span class="filename">Filename: Cargo.toml</span> | |
363 | ||
364 | ```toml | |
365 | [package] | |
366 | name = "guessing_game" | |
367 | version = "0.1.0" | |
a2a8927a | 368 | edition = "2021" |
13cf67c4 XL |
369 | description = "A fun game where you guess what number the computer has chosen." |
370 | license = "MIT OR Apache-2.0" | |
371 | ||
372 | [dependencies] | |
373 | ``` | |
374 | ||
375 | [Cargo’s documentation](https://doc.rust-lang.org/cargo/) describes other | |
376 | metadata you can specify to ensure others can discover and use your crate more | |
377 | easily. | |
378 | ||
379 | ### Publishing to Crates.io | |
380 | ||
381 | Now that you’ve created an account, saved your API token, chosen a name for | |
382 | your crate, and specified the required metadata, you’re ready to publish! | |
383 | Publishing a crate uploads a specific version to | |
dc9dc135 | 384 | [crates.io](https://crates.io/)<!-- ignore --> for others to use. |
13cf67c4 | 385 | |
04454e1e FG |
386 | Be careful, because a publish is *permanent*. The version can never be |
387 | overwritten, and the code cannot be deleted. One major goal of | |
388 | [crates.io](https://crates.io/)<!-- ignore --> is to act as a permanent archive | |
389 | of code so that builds of all projects that depend on crates from | |
dc9dc135 | 390 | [crates.io](https://crates.io/)<!-- ignore --> will continue to work. Allowing |
13cf67c4 XL |
391 | version deletions would make fulfilling that goal impossible. However, there is |
392 | no limit to the number of crate versions you can publish. | |
393 | ||
394 | Run the `cargo publish` command again. It should succeed now: | |
395 | ||
74b04a01 XL |
396 | <!-- manual-regeneration |
397 | go to some valid crate, publish a new version | |
398 | cargo publish | |
399 | copy just the relevant lines below | |
400 | --> | |
401 | ||
f035d41b | 402 | ```console |
13cf67c4 | 403 | $ cargo publish |
74b04a01 XL |
404 | Updating crates.io index |
405 | Packaging guessing_game v0.1.0 (file:///projects/guessing_game) | |
406 | Verifying guessing_game v0.1.0 (file:///projects/guessing_game) | |
407 | Compiling guessing_game v0.1.0 | |
13cf67c4 | 408 | (file:///projects/guessing_game/target/package/guessing_game-0.1.0) |
74b04a01 XL |
409 | Finished dev [unoptimized + debuginfo] target(s) in 0.19s |
410 | Uploading guessing_game v0.1.0 (file:///projects/guessing_game) | |
13cf67c4 XL |
411 | ``` |
412 | ||
413 | Congratulations! You’ve now shared your code with the Rust community, and | |
414 | anyone can easily add your crate as a dependency of their project. | |
415 | ||
416 | ### Publishing a New Version of an Existing Crate | |
417 | ||
418 | When you’ve made changes to your crate and are ready to release a new version, | |
419 | you change the `version` value specified in your *Cargo.toml* file and | |
420 | republish. Use the [Semantic Versioning rules][semver] to decide what an | |
421 | appropriate next version number is based on the kinds of changes you’ve made. | |
422 | Then run `cargo publish` to upload the new version. | |
423 | ||
04454e1e FG |
424 | <!-- Old link, do not remove --> |
425 | <a id="removing-versions-from-cratesio-with-cargo-yank"></a> | |
13cf67c4 | 426 | |
04454e1e | 427 | ### Deprecating Versions from Crates.io with `cargo yank` |
13cf67c4 XL |
428 | |
429 | Although you can’t remove previous versions of a crate, you can prevent any | |
430 | future projects from adding them as a new dependency. This is useful when a | |
431 | crate version is broken for one reason or another. In such situations, Cargo | |
432 | supports *yanking* a crate version. | |
433 | ||
04454e1e FG |
434 | Yanking a version prevents new projects from depending on that version while |
435 | allowing all existing projects that depend on it to continue. Essentially, a | |
436 | yank means that all projects with a *Cargo.lock* will not break, and any future | |
437 | *Cargo.lock* files generated will not use the yanked version. | |
13cf67c4 | 438 | |
04454e1e FG |
439 | To yank a version of a crate, in the directory of the crate that you’ve |
440 | previously published, run `cargo yank` and specify which version you want to | |
923072b8 FG |
441 | yank. For example, if we've published a crate named `guessing_game` version |
442 | 1.0.1 and we want to yank it, in the project directory for `guessing_game` we'd | |
443 | run: | |
13cf67c4 | 444 | |
f035d41b | 445 | ```console |
13cf67c4 | 446 | $ cargo yank --vers 1.0.1 |
923072b8 FG |
447 | Updating crates.io index |
448 | Yank guessing_game:1.0.1 | |
13cf67c4 XL |
449 | ``` |
450 | ||
451 | By adding `--undo` to the command, you can also undo a yank and allow projects | |
452 | to start depending on a version again: | |
453 | ||
f035d41b | 454 | ```console |
13cf67c4 | 455 | $ cargo yank --vers 1.0.1 --undo |
923072b8 FG |
456 | Updating crates.io index |
457 | Unyank guessing_game_:1.0.1 | |
13cf67c4 XL |
458 | ``` |
459 | ||
04454e1e FG |
460 | A yank *does not* delete any code. It cannot, for example, delete accidentally |
461 | uploaded secrets. If that happens, you must reset those secrets immediately. | |
462 | ||
463 | [spdx]: http://spdx.org/licenses/ | |
464 | [semver]: http://semver.org/ |