Skip to content

Commit 1762714

Browse files
authored
feat: Add support for additional package manifest keys (#6868)
## Description Adds new keys to the package manifest's project section. These will be used when publishing packages. ## Checklist - [ ] I have linked to any relevant issues. - [ ] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [ ] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [ ] I have requested a review from the relevant team or maintainers.
1 parent 1194375 commit 1762714

File tree

2 files changed

+82
-16
lines changed

2 files changed

+82
-16
lines changed

docs/book/src/forc/manifest_reference.md

+16-1
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@ The `Forc.toml` (the _manifest_ file) is a compulsory file for each package and
44

55
* [`[project]`](#the-project-section) — Defines a sway project.
66
* `name` — The name of the project.
7+
* `version` — The version of the project.
8+
* `description` — A description of the project.
79
* `authors` — The authors of the project.
810
* `organization` — The organization of the project.
9-
* `license`— The project license.
11+
* `license` — The project license.
12+
* `homepage` — URL of the project homepage.
13+
* `repository` — URL of the project source repository.
14+
* `documentation` — URL of the project documentation.
1015
* `entry` — The entry point for the compiler to start parsing from.
1116
* For the recommended way of selecting an entry point of large libraries please take a look at: [Libraries](./../sway-program-types/libraries.md)
1217
* `implicit-std` - Controls whether provided `std` version (with the current `forc` version) will get added as a dependency _implicitly_. _Unless you know what you are doing, leave this as default._
@@ -29,6 +34,11 @@ An example `Forc.toml` is shown below. Under `[project]` the following fields ar
2934

3035
* `authors`
3136
* `organization`
37+
* `version`
38+
* `description`
39+
* `homepage`
40+
* `repository`
41+
* `documentation`
3242

3343
Also for the following fields, a default value is provided so omitting them is allowed:
3444

@@ -39,6 +49,11 @@ Also for the following fields, a default value is provided so omitting them is a
3949
[project]
4050
authors = ["user"]
4151
entry = "main.sw"
52+
description = "Wallet contract"
53+
version = "1.0.0"
54+
homepage = "https://example.com/"
55+
repository = "https://example.com/"
56+
documentation = "https://example.com/"
4257
organization = "Fuel_Labs"
4358
license = "Apache-2.0"
4459
name = "wallet_contract"

forc-pkg/src/manifest/mod.rs

+66-15
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use crate::pkg::{manifest_file_missing, parsing_failed, wrong_program_type};
44
use anyhow::{anyhow, bail, Context, Result};
55
use forc_tracing::println_warning;
66
use forc_util::{validate_name, validate_project_name};
7-
use serde::{Deserialize, Serialize};
7+
use semver::Version;
8+
use serde::{de, Deserialize, Serialize};
89
use serde_with::{serde_as, DisplayFromStr};
910
use std::{
1011
collections::{BTreeMap, HashMap},
@@ -19,6 +20,7 @@ use sway_utils::{
1920
constants, find_nested_manifest_dir, find_parent_manifest_dir,
2021
find_parent_manifest_dir_with_check,
2122
};
23+
use url::Url;
2224

2325
use self::build_profile::BuildProfile;
2426

@@ -193,9 +195,15 @@ pub struct PackageManifest {
193195
#[serde(rename_all = "kebab-case")]
194196
pub struct Project {
195197
pub authors: Option<Vec<String>>,
198+
#[serde(deserialize_with = "validate_package_name")]
196199
pub name: String,
200+
pub version: Option<Version>,
201+
pub description: Option<String>,
197202
pub organization: Option<String>,
198203
pub license: String,
204+
pub homepage: Option<Url>,
205+
pub repository: Option<Url>,
206+
pub documentation: Option<Url>,
199207
#[serde(default = "default_entry")]
200208
pub entry: String,
201209
pub implicit_std: Option<bool>,
@@ -205,6 +213,18 @@ pub struct Project {
205213
pub metadata: Option<toml::Value>,
206214
}
207215

216+
// Validation function for the `name` field
217+
fn validate_package_name<'de, D>(deserializer: D) -> Result<String, D::Error>
218+
where
219+
D: de::Deserializer<'de>,
220+
{
221+
let name: String = Deserialize::deserialize(deserializer)?;
222+
match validate_project_name(&name) {
223+
Ok(_) => Ok(name),
224+
Err(e) => Err(de::Error::custom(e.to_string())),
225+
}
226+
}
227+
208228
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
209229
#[serde(rename_all = "kebab-case")]
210230
pub struct Network {
@@ -318,6 +338,14 @@ impl Dependency {
318338
Self::Detailed(ref det) => det.package.as_deref(),
319339
}
320340
}
341+
342+
/// The string of the `version` field if specified.
343+
pub fn version(&self) -> Option<&str> {
344+
match *self {
345+
Self::Simple(ref version) => Some(version),
346+
Self::Detailed(ref det) => det.version.as_deref(),
347+
}
348+
}
321349
}
322350

323351
impl PackageManifestFile {
@@ -571,10 +599,25 @@ impl PackageManifest {
571599
// package or a workspace. While doing so, we should be printing the warnings if the given
572600
// file parses so that we only see warnings for the correct type of manifest.
573601
let path = path.as_ref();
574-
let mut warnings = vec![];
575-
let manifest_str = std::fs::read_to_string(path)
602+
let contents = std::fs::read_to_string(path)
576603
.map_err(|e| anyhow!("failed to read manifest at {:?}: {}", path, e))?;
577-
let toml_de = toml::de::Deserializer::new(&manifest_str);
604+
Self::from_string(contents)
605+
}
606+
607+
/// Given a path to a `Forc.toml`, read it and construct a `PackageManifest`.
608+
///
609+
/// This also `validate`s the manifest, returning an `Err` in the case that invalid names,
610+
/// fields were used.
611+
///
612+
/// If `core` and `std` are unspecified, `std` will be added to the `dependencies` table
613+
/// implicitly. In this case, the git tag associated with the version of this crate is used to
614+
/// specify the pinned commit at which we fetch `std`.
615+
pub fn from_string(contents: String) -> Result<Self> {
616+
// While creating a `ManifestFile` we need to check if the given path corresponds to a
617+
// package or a workspace. While doing so, we should be printing the warnings if the given
618+
// file parses so that we only see warnings for the correct type of manifest.
619+
let mut warnings = vec![];
620+
let toml_de = toml::de::Deserializer::new(&contents);
578621
let mut manifest: Self = serde_ignored::deserialize(toml_de, |path| {
579622
let warning = format!("unused manifest key: {path}");
580623
warnings.push(warning);
@@ -1338,6 +1381,11 @@ mod tests {
13381381
let project = Project {
13391382
authors: Some(vec!["Test Author".to_string()]),
13401383
name: "test-project".to_string(),
1384+
version: Some(Version::parse("0.1.0").unwrap()),
1385+
description: Some("test description".to_string()),
1386+
homepage: None,
1387+
documentation: None,
1388+
repository: None,
13411389
organization: None,
13421390
license: "Apache-2.0".to_string(),
13431391
entry: "main.sw".to_string(),
@@ -1359,6 +1407,11 @@ mod tests {
13591407
let project = Project {
13601408
authors: Some(vec!["Test Author".to_string()]),
13611409
name: "test-project".to_string(),
1410+
version: Some(Version::parse("0.1.0").unwrap()),
1411+
description: Some("test description".to_string()),
1412+
homepage: Some(Url::parse("https://example.com").unwrap()),
1413+
documentation: Some(Url::parse("https://docs.example.com").unwrap()),
1414+
repository: Some(Url::parse("https://example.com").unwrap()),
13621415
organization: None,
13631416
license: "Apache-2.0".to_string(),
13641417
entry: "main.sw".to_string(),
@@ -1372,6 +1425,11 @@ mod tests {
13721425
let deserialized: Project = toml::from_str(&serialized).unwrap();
13731426

13741427
assert_eq!(project.name, deserialized.name);
1428+
assert_eq!(project.version, deserialized.version);
1429+
assert_eq!(project.description, deserialized.description);
1430+
assert_eq!(project.homepage, deserialized.homepage);
1431+
assert_eq!(project.documentation, deserialized.documentation);
1432+
assert_eq!(project.repository, deserialized.repository);
13751433
assert_eq!(project.metadata, deserialized.metadata);
13761434
assert_eq!(project.metadata, None);
13771435
}
@@ -1383,13 +1441,11 @@ mod tests {
13831441
license = "Apache-2.0"
13841442
entry = "main.sw"
13851443
authors = ["Test Author"]
1386-
1387-
[metadata]
13881444
description = "A test project"
13891445
version = "1.0.0"
1390-
homepage = "https://example.com"
1391-
documentation = "https://docs.example.com"
1392-
repository = "https://github.com/example/test-project"
1446+
1447+
[metadata]
1448+
mykey = "https://example.com"
13931449
keywords = ["test", "project"]
13941450
categories = ["test"]
13951451
"#;
@@ -1401,12 +1457,7 @@ mod tests {
14011457
let table = metadata.as_table().unwrap();
14021458

14031459
assert_eq!(
1404-
table.get("description").unwrap().as_str().unwrap(),
1405-
"A test project"
1406-
);
1407-
assert_eq!(table.get("version").unwrap().as_str().unwrap(), "1.0.0");
1408-
assert_eq!(
1409-
table.get("homepage").unwrap().as_str().unwrap(),
1460+
table.get("mykey").unwrap().as_str().unwrap(),
14101461
"https://example.com"
14111462
);
14121463

0 commit comments

Comments
 (0)