Skip to content

Commit

Permalink
feat: check for exposing multiple modules on publish
Browse files Browse the repository at this point in the history
  • Loading branch information
Guria authored and lpil committed Dec 2, 2024
1 parent 34cdbb5 commit 639b4f6
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 1 deletion.
4 changes: 4 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,10 @@ jobs:
run: make test
working-directory: ./test/running_modules

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

- name: Test FFI in subdirectories
run: make
working-directory: ./test/subdir_ffi
47 changes: 46 additions & 1 deletion compiler-cli/src/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use gleam_core::{
build::{Codegen, Compile, Mode, Options, Package, Target},
config::{PackageConfig, SpdxLicense},
docs::DocContext,
error::SmallVersion,
error::{wrap, SmallVersion},
hex,
paths::{self, ProjectPaths},
requirement::Requirement,
Expand Down Expand Up @@ -56,6 +56,7 @@ impl PublishCommand {
} = do_build_hex_tarball(&paths, &mut config)?;

check_for_name_squatting(&compile_result)?;
check_for_multiple_top_level_modules(&compile_result, i_am_sure)?;

// Build HTML documentation
let docs_tarball = fs::create_tar_archive(docs::build_documentation(
Expand Down Expand Up @@ -123,6 +124,50 @@ fn check_for_name_squatting(package: &Package) -> Result<(), Error> {
Ok(())
}

fn check_for_multiple_top_level_modules(package: &Package, i_am_sure: bool) -> Result<(), Error> {
// Collect top-level module names
let mut top_level_module_names = package
.modules
.iter()
.filter_map(|module| module.name.split('/').next())
.collect::<Vec<_>>();

// Remove duplicates
top_level_module_names.sort_unstable();
top_level_module_names.dedup();

// If more than one top-level module name is found, prompt for confirmation
if top_level_module_names.len() > 1 {
let text = wrap(&format!(
"Your package defines multiple top-level modules: {}.
Defining multiple top-level modules can lead to namespace pollution \
and potential conflicts for consumers.
To fix this, move all your modules under a single top-level module of your choice.
For example:
src/{1}.gleam
src/{1}/module1.gleam
src/{1}/module2.gleam",
top_level_module_names.join(", "),
package.config.name
));
println!("{text}\n");

let should_publish =
i_am_sure || cli::confirm("\nDo you wish to continue publishing this package?")?;
println!();

if !should_publish {
println!("Not publishing.");
std::process::exit(0);
}
}

Ok(())
}

fn check_repo_url(config: &PackageConfig, i_am_sure: bool) -> Result<bool, Error> {
let Some(url) = config.repository.url() else {
return Ok(true);
Expand Down
3 changes: 3 additions & 0 deletions test/multi_namespace/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.beam
*.ez
build
4 changes: 4 additions & 0 deletions test/multi_namespace/gleam.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name = "multi_namespace"
version = "1.0.0"
description = "Test project for multi namespace"
licences = ["Apache-2.0"]
7 changes: 7 additions & 0 deletions test/multi_namespace/manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# This file was generated by Gleam
# You typically do not need to edit this file

packages = [
]

[requirements]
3 changes: 3 additions & 0 deletions test/multi_namespace/src/multi_namespace.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn main() {
"Hello from multi_namespace!"
}
3 changes: 3 additions & 0 deletions test/multi_namespace/src/second.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn main() {
"Hello from second!"
}
26 changes: 26 additions & 0 deletions test/multi_namespace/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/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
output=$(yes "n" | g publish)
if echo "$output" | grep -q "Your package defines multiple top-level modules"; then
echo "Publish was correctly prevented with warning"
else
echo "Expected publish to be aborted"
exit 1
fi

echo
echo Success! 💖
echo

0 comments on commit 639b4f6

Please sign in to comment.