Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -474,15 +474,15 @@ jobs:
run: make test
working-directory: ./test/hextarball

- name: Test running modules
- name: test/running_modules
run: make test-all
working-directory: ./test/running_modules

- name: test/multi_namespace
run: ./test.sh
working-directory: ./test/multi_namespace

- name: Test multi namespace bug
- name: test/multi_namespace_not_top_level
run: ./test.sh
working-directory: ./test/multi_namespace_not_top_level

Expand Down
12 changes: 10 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
([Louis Pilfold](https://github.com/lpil))

- The build tool now emits errors for unknown fields in package config,
except ones under `[tools]`. For example, with this:
except for the ones under `[tools]`. For example, with this:

```toml
name = "hello"
Expand All @@ -58,7 +58,7 @@
my-awesome-setting = true
```

Building the project will emit error.
Building the project will emit an error.

([Andrey Kozhev](https://github.com/ankddev))

Expand All @@ -70,6 +70,14 @@
arguments by taking into account, whether it's a function or a constructor.
([Andrey Kozhev](https://github.com/ankddev))

- The build tool will now refuse to publish any package that has the default
README generated by the `gleam new` command.
([Giacomo Cavalieri](https://github.com/giacomocavalieri))

- The build tool will now refuse to publish any package that has no README, or
an empty README.
([Giacomo Cavalieri](https://github.com/giacomocavalieri))

### Language server

- The language server now allows extracting the start of a pipeline into a
Expand Down
59 changes: 31 additions & 28 deletions compiler-cli/src/new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,34 +84,7 @@ impl FileToCreate {
};

match self {
Self::Readme => Some(format!(
r#"# {project_name}

[![Package Version](https://img.shields.io/hexpm/v/{project_name})](https://hex.pm/packages/{project_name})
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/{project_name}/)

```sh
gleam add {project_name}@1
```
```gleam
import {project_name}

pub fn main() -> Nil {{
// TODO: An example of the project in use
}}
```

Further documentation can be found at <https://hexdocs.pm/{project_name}>.

## Development

```sh
gleam run # Run the project
gleam test # Run the tests
```
"#,
)),

Self::Readme => Some(default_readme(project_name)),
Self::Gitignore if !skip_git => Some(
"*.beam
*.ez
Expand Down Expand Up @@ -202,6 +175,36 @@ jobs:
}
}

pub fn default_readme(project_name: &str) -> String {
format!(
r#"# {project_name}

[![Package Version](https://img.shields.io/hexpm/v/{project_name})](https://hex.pm/packages/{project_name})
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/{project_name}/)

```sh
gleam add {project_name}@1
```
```gleam
import {project_name}

pub fn main() -> Nil {{
// TODO: An example of the project in use
}}
```

Further documentation can be found at <https://hexdocs.pm/{project_name}>.

## Development

```sh
gleam run # Run the project
gleam test # Run the tests
```
"#,
)
}

impl Creator {
fn new(options: NewOptions, gleam_version: &'static str) -> Result<Self, Error> {
Self::new_with_confirmation(options, gleam_version, crate::cli::confirm)
Expand Down
45 changes: 43 additions & 2 deletions compiler-cli/src/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use gleam_core::{
build::{Codegen, Compile, Mode, Options, Package, Target},
config::{GleamVersion, PackageConfig, SpdxLicense},
docs::{Dependency, DependencyKind, DocContext},
error::{SmallVersion, wrap},
error::{InvalidReadmeReason, SmallVersion, wrap},
hex,
manifest::ManifestPackageSource,
paths::{self, ProjectPaths},
Expand All @@ -20,7 +20,7 @@ use itertools::Itertools;
use sha2::Digest;
use std::{collections::HashMap, io::Write, path::PathBuf, time::Instant};

use crate::{build, cli, docs, fs, http::HttpClient};
use crate::{build, cli, docs, fs, http::HttpClient, new::default_readme};

const CORE_TEAM_PUBLISH_PASSWORD: &str = "Trans rights are human rights";

Expand All @@ -31,6 +31,8 @@ pub fn command(paths: &ProjectPaths, replace: bool, i_am_sure: bool) -> Result<(
&& check_for_version_zero(&config)?
&& check_repo_url(&config, i_am_sure)?;

check_for_invalid_readme(&config, paths)?;

if !should_publish {
println!("Not publishing.");
return Ok(());
Expand Down Expand Up @@ -130,6 +132,45 @@ HTML documentation will work:
Ok(())
}

fn check_for_invalid_readme(config: &PackageConfig, paths: &ProjectPaths) -> Result<(), Error> {
let normalise = |string: String| {
string
.trim()
.replace("\r\n", "")
.replace("\n", "")
.replace("\t", "")
.replace(" ", "")
};

let project_readme = match fs::read(paths.readme()) {
Err(Error::FileIo {
err: Some(message), ..
}) if message.contains("No such file or directory") => {
return Err(Error::CannotPublishWithInvalidReadme {
reason: InvalidReadmeReason::Missing,
});
}
Err(error) => return Err(error),
Ok(project_readme) => project_readme,
};

let normalised_project_readme = normalise(project_readme);
if normalised_project_readme.is_empty() {
return Err(Error::CannotPublishWithInvalidReadme {
reason: InvalidReadmeReason::Empty,
});
}

let default_readme = default_readme(config.name.as_str());
if normalised_project_readme == normalise(default_readme) {
return Err(Error::CannotPublishWithInvalidReadme {
reason: InvalidReadmeReason::Default,
});
}

Ok(())
}

fn check_for_name_squatting(package: &Package) -> Result<(), Error> {
if package.modules.len() > 1 {
return Ok(());
Expand Down
67 changes: 67 additions & 0 deletions compiler-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,9 @@ file_names.iter().map(|x| x.as_str()).join(", "))]
#[error("The modules {unfinished:?} are empty and so cannot be published")]
CannotPublishEmptyModules { unfinished: Vec<EcoString> },

#[error("Publishing packages with an invalid README is not permitted")]
CannotPublishWithInvalidReadme { reason: InvalidReadmeReason },

#[error("Publishing packages to reserve names is not permitted")]
HexPackageSquatting,

Expand Down Expand Up @@ -346,6 +349,13 @@ file_names.iter().map(|x| x.as_str()).join(", "))]
CannotAddSelfAsDependency { name: EcoString },
}

#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum InvalidReadmeReason {
Missing,
Empty,
Default,
}

// A wrapper that ignores the inner value for equality:
#[derive(Debug, Clone)]
pub struct NeverEqual<T>(pub T);
Expand Down Expand Up @@ -862,6 +872,63 @@ package deletion or account suspension.
}]
}

Error::CannotPublishWithInvalidReadme {
reason: InvalidReadmeReason::Default,
} => {
let text =
"You appear to be attempting to publish a package with the default README
generated by the `gleam new` command. That is meant as a placeholder and a
published package should have its own carefully written README.
"
.into();

vec![Diagnostic {
title: "Cannot publish with default README".into(),
text,
level: Level::Error,
location: None,
hint: Some(
"Update your project's README to describe it before publishing".into(),
),
}]
}

Error::CannotPublishWithInvalidReadme {
reason: InvalidReadmeReason::Missing,
} => {
let text = "You appear to be attempting to publish a package with no README.
All published packages should have one.
"
.into();

vec![Diagnostic {
title: "Cannot publish with no README".into(),
text,
level: Level::Error,
location: None,
hint: Some("Add a README to your project before publishing.".into()),
}]
}

Error::CannotPublishWithInvalidReadme {
reason: InvalidReadmeReason::Empty,
} => {
let text = "You appear to be attempting to publish a package with an empty README.
All published packages should have a non empty README.
"
.into();

vec![Diagnostic {
title: "Cannot publish with empty README".into(),
text,
level: Level::Error,
location: None,
hint: Some(
"Update your project's README to describe it before publishing".into(),
),
}]
}

Error::CannotPublishWithDefaultMain { package_name } => {
let text = wrap_format!(
"Packages with the default main function cannot be published
Expand Down
3 changes: 3 additions & 0 deletions test/multi_namespace/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Multi namespace project

should not be published!
3 changes: 3 additions & 0 deletions test/multi_namespace_not_top_level/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Multi namespace project

should not be published!
3 changes: 3 additions & 0 deletions test/publishing_default_readme/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.beam
*.ez
build
24 changes: 24 additions & 0 deletions test/publishing_default_readme/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# default_readme

[![Package Version](https://img.shields.io/hexpm/v/default_readme)](https://hex.pm/packages/default_readme)
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/default_readme/)

```sh
gleam add default_readme@1
```
```gleam
import default_readme

pub fn main() -> Nil {
// TODO: An example of the project in use
}
```

Further documentation can be found at <https://hexdocs.pm/default_readme>.

## Development

```sh
gleam run # Run the project
gleam test # Run the tests
```
7 changes: 7 additions & 0 deletions test/publishing_default_readme/gleam.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
name = "default_readme"
version = "1.0.0"
description = "Test project for default readme"
licences = ["Apache-2.0"]

[dependencies]
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
9 changes: 9 additions & 0 deletions test/publishing_default_readme/manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# This file was generated by Gleam
# You typically do not need to edit this file

packages = [
{ name = "gleam_stdlib", version = "0.62.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "0080706D3A5A9A36C40C68481D1D231D243AF602E6D2A2BE67BA8F8F4DFF45EC" },
]

[requirements]
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
21 changes: 21 additions & 0 deletions test/publishing_default_readme/src/default_readme.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import gleam/io

/// This tests that a project with a default readme doesn't get published.
///
pub fn main() -> Nil {
greeting()
first_line()
second_line()
}

fn greeting() {
io.println("Hello from default_readme!")
}

fn first_line() {
io.println("Here we have some additional code so that this is not mistaken")
}

fn second_line() {
io.println("for a default main project, that would be rejected as well!")
}
23 changes: 23 additions & 0 deletions test/publishing_default_readme/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/sh

set -eu

GLEAM_COMMAND=${GLEAM_COMMAND:-"cargo run --quiet --"}

g() {
echo "Running: $GLEAM_COMMAND $@"
$GLEAM_COMMAND "$@"
}

echo Resetting the build directory to get to a known state
rm -fr build

echo Running publish should not publish anything
if yes "n" | g publish; then
echo "Expected publish to fail, but it succeeded"
exit 1
fi

echo
echo Success! 💖
echo
3 changes: 3 additions & 0 deletions test/publishing_empty_readme/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.beam
*.ez
build
Empty file.
7 changes: 7 additions & 0 deletions test/publishing_empty_readme/gleam.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
name = "empty_readme"
version = "1.0.0"
description = "Test project for empty readme"
licences = ["Apache-2.0"]

[dependencies]
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
Loading
Loading