Skip to content

Support the purs.json manifest in purs publish#4233

Merged
JordanMartinez merged 17 commits intomasterfrom
trh/purs-publish
Feb 25, 2022
Merged

Support the purs.json manifest in purs publish#4233
JordanMartinez merged 17 commits intomasterfrom
trh/purs-publish

Conversation

@thomashoneyman
Copy link
Copy Markdown
Member

@thomashoneyman thomashoneyman commented Feb 12, 2022

Description of the change

Fixes #4231 by adding partial support for the PureScript registry manifest format to purs publish. We can only provide partial support for packages using the PureScript registry because both purs publish and Pursuit bake in assumptions about package structure and location that the registry does not require. For example:

  • purs publish and Pursuit require that packages are published to GitHub. The registry doesn't restrict where a package can be published, so long as it is publicly accessible.
  • purs publish and Pursuit require that packages specify their version via a SemVer-compliant Git tag such as v1.0.0. The registry allows packages to use any ref to associate with a package version, and takes the version from the version field in the package manifest.
  • As a consequence of that last point, purs publish and Pursuit require every package to be stored in their own repository on GitHub. The registry supports monorepos, where several packages can be published from one repository (hence why a Git tag can't be used to assert a particular package's version).

It isn't possible to support publishing packages that take advantage of these features of the PureScript registry using purs publish without introducing breaking changes. Instead, this PR provides a compatibility layer in which we:

  1. Accept purs.json files as a manifest format
  2. Convert the parsed manifest into a valid Bower PackageMeta
  3. Proceed through the existing Bower publishing pipeline

Checklist:

  • Added a file to CHANGELOG.d for this PR (see CHANGELOG.d/README.md)
  • Added myself to CONTRIBUTORS.md (if this is my first contribution)
  • Linked any existing issues or proposals that this pull request should close
  • Updated or added relevant documentation
  • Added a test for the contribution (if applicable)

@JordanMartinez JordanMartinez mentioned this pull request Feb 18, 2022
5 tasks
@thomashoneyman thomashoneyman mentioned this pull request Feb 23, 2022
5 tasks
Copy link
Copy Markdown
Contributor

@JordanMartinez JordanMartinez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some overall comments. This looks good to me, but I haven't pulled it down locally and tried it out yet.

@JordanMartinez
Copy link
Copy Markdown
Contributor

So long as the tests pass, this will get an approval from me.

@thomashoneyman thomashoneyman marked this pull request as ready for review February 24, 2022 03:00
@thomashoneyman
Copy link
Copy Markdown
Member Author

thomashoneyman commented Feb 24, 2022

For anyone who would like to test this out locally you can follow the steps below. I'm assuming you've already built this branch and have access to the resulting purs executable in your PATH or via pointing at the executable path Stack prints after a successful build.


First, clone the slug repo:

$ git clone git@github.com:thomashoneyman/purescript-slug
$ cd purescript-slug

Next, check out the v3.0.1 tag and install dependencies:

$ git checkout v3.0.1
$ spago install

Then, add the following purs.json file to the repository:

{
  "name": "slug",
  "version": "3.0.1",
  "license": "MIT",
  "location": {
    "githubOwner": "thomashoneyman",
    "githubRepo": "purescript-slug"
  },
  "dependencies": {
    "argonaut-codecs": ">=8.0.0 <9.0.0",
    "arrays": ">=6.0.0 <7.0.0",
    "either": ">=5.0.0 <6.0.0",
    "maybe": ">=5.0.0 <6.0.0",
    "prelude": ">=5.0.0 <6.0.0",
    "strings": ">=5.0.0 <6.0.0",
    "unicode": ">=5.0.0 <6.0.0"
  }
}

Finally, add the following resolutions.json file somewhere in your filesystem, but not in your repository:

{
  "purescript-argonaut-codecs": {
    "path": ".spago/argonaut-codecs/v8.0.0"
  },
  "purescript-argonaut-core": {
    "path": ".spago/argonaut-core/v6.0.0"
  },
  "purescript-arrays": {
    "path": ".spago/arrays/v6.0.0"
  },
  "purescript-bifunctors": {
    "path": ".spago/bifunctors/v5.0.0"
  },
  "purescript-const": {
    "path": ".spago/const/v5.0.0"
  },
  "purescript-contravariant": {
    "path": ".spago/contravariant/v5.0.0"
  },
  "purescript-control": {
    "path": ".spago/control/v5.0.0"
  },
  "purescript-distributive": {
    "path": ".spago/distributive/v5.0.0"
  },
  "purescript-effect": {
    "path": ".spago/effect/v3.0.0"
  },
  "purescript-either": {
    "path": ".spago/either/v5.0.0"
  },
  "purescript-enums": {
    "path": ".spago/enums/v5.0.0"
  },
  "purescript-exists": {
    "path": ".spago/exists/v5.0.0"
  },
  "purescript-foldable-traversable": {
    "path": ".spago/foldable-traversable/v5.0.0"
  },
  "purescript-foreign-object": {
    "path": ".spago/foreign-object/v3.0.0"
  },
  "purescript-functions": {
    "path": ".spago/functions/v5.0.0"
  },
  "purescript-functors": {
    "path": ".spago/functors/v4.0.0"
  },
  "purescript-gen": {
    "path": ".spago/gen/v3.0.0"
  },
  "purescript-identity": {
    "path": ".spago/identity/v5.0.0"
  },
  "purescript-integers": {
    "path": ".spago/integers/v5.0.0"
  },
  "purescript-invariant": {
    "path": ".spago/invariant/v5.0.0"
  },
  "purescript-lazy": {
    "path": ".spago/lazy/v5.0.0"
  },
  "purescript-lists": {
    "path": ".spago/lists/v6.0.0"
  },
  "purescript-math": {
    "path": ".spago/math/v3.0.0"
  },
  "purescript-maybe": {
    "path": ".spago/maybe/v5.0.0"
  },
  "purescript-newtype": {
    "path": ".spago/newtype/v4.0.0"
  },
  "purescript-nonempty": {
    "path": ".spago/nonempty/v6.0.0"
  },
  "purescript-numbers": {
    "path": ".spago/numbers/v8.0.0"
  },
  "purescript-ordered-collections": {
    "path": ".spago/ordered-collections/v2.0.0"
  },
  "purescript-orders": {
    "path": ".spago/orders/v5.0.0"
  },
  "purescript-partial": {
    "path": ".spago/partial/v3.0.0"
  },
  "purescript-prelude": {
    "path": ".spago/prelude/v5.0.0"
  },
  "purescript-profunctor": {
    "path": ".spago/profunctor/v5.0.0"
  },
  "purescript-record": {
    "path": ".spago/record/v3.0.0"
  },
  "purescript-refs": {
    "path": ".spago/refs/v5.0.0"
  },
  "purescript-safe-coerce": {
    "path": ".spago/safe-coerce/v1.0.0"
  },
  "purescript-st": {
    "path": ".spago/st/v5.0.0"
  },
  "purescript-strings": {
    "path": ".spago/strings/v5.0.0"
  },
  "purescript-tailrec": {
    "path": ".spago/tailrec/v5.0.0"
  },
  "purescript-tuples": {
    "path": ".spago/tuples/v6.0.0"
  },
  "purescript-type-equality": {
    "path": ".spago/type-equality/v4.0.0"
  },
  "purescript-typelevel-prelude": {
    "path": ".spago/typelevel-prelude/v6.0.0"
  },
  "purescript-unfoldable": {
    "path": ".spago/unfoldable/v5.0.0"
  },
  "purescript-unicode": {
    "path": ".spago/unicode/v5.0.0"
  },
  "purescript-unsafe-coerce": {
    "path": ".spago/unsafe-coerce/v5.0.0"
  }
}

At this point, you should have both files required for publishing, and your git tree should be dirty with only the .purs.json untracked file:

$ git status
HEAD detached at v3.0.1
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .purs.json

nothing added to commit but untracked files present (use "git add" to track)

Finally, you can publish the library (here, assuming that the resolutions file is in the parent directory):

purs publish --manifest .purs.json --resolutions ../resolutions.json

This will yield the following successful publish result:

{"uploader":null,"packageMeta":{"homepage":"https://github.com/thomashoneyman/purescript-slug.git","repository":{"url":"https://github.com/thomashoneyman/purescript-slug.git","type":"git"},"dependencies":{"purescript-unicode":">=5.0.0 <6.0.0","purescript-either":">=5.0.0 <6.0.0","purescript-arrays":">=6.0.0 <7.0.0","purescript-maybe":">=5.0.0 <6.0.0","purescript-prelude":">=5.0.0 <6.0.0","purescript-argonaut-codecs":">=8.0.0 <9.0.0","purescript-strings":">=5.0.0 <6.0.0"},"name":"purescript-slug","license":["MIT"]},"tagTime":"2022-02-24T02:38:22+0000","modules":[{"reExports":[],"name":"Slug","comments":null,"declarations":[{"kind":null,"children":[{"comments":null,"title":"eqSlug","info":{"declType":"instance","dependencies":[],"type":{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Data","Eq"],"Eq"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Slug"],"Slug"]}]}},"sourceSpan":{"start":[33,1],"name":"/Users/trh/Desktop/purescript-slug/src/Slug.purs","end":[33,34]}},{"comments":null,"title":"ordSlug","info":{"declType":"instance","dependencies":[],"type":{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Data","Ord"],"Ord"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Slug"],"Slug"]}]}},"sourceSpan":{"start":[34,1],"name":"/Users/trh/Desktop/purescript-slug/src/Slug.purs","end":[34,36]}},{"comments":null,"title":"semigroupSlug","info":{"declType":"instance","dependencies":[],"type":{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Data","Semigroup"],"Semigroup"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Slug"],"Slug"]}]}},"sourceSpan":{"start":[35,1],"name":"/Users/trh/Desktop/purescript-slug/src/Slug.purs","end":[35,56]}},{"comments":null,"title":"showSlug","info":{"declType":"instance","dependencies":[],"type":{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Data","Show"],"Show"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Slug"],"Slug"]}]}},"sourceSpan":{"start":[37,1],"name":"/Users/trh/Desktop/purescript-slug/src/Slug.purs","end":[38,43]}},{"comments":null,"title":"encodeJsonSlug","info":{"declType":"instance","dependencies":[],"type":{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Data","Argonaut","Encode","Class"],"EncodeJson"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Slug"],"Slug"]}]}},"sourceSpan":{"start":[40,1],"name":"/Users/trh/Desktop/purescript-slug/src/Slug.purs","end":[41,37]}},{"comments":null,"title":"decodeJsonSlug","info":{"declType":"instance","dependencies":[],"type":{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Data","Argonaut","Decode","Class"],"DecodeJson"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Slug"],"Slug"]}]}},"sourceSpan":{"start":[43,1],"name":"/Users/trh/Desktop/purescript-slug/src/Slug.purs","end":[44,67]}}],"comments":"A `Slug` represents a string value which is guaranteed to have the\nfollowing qualities:\n\n- it is not empty\n- it consists of alphanumeric groups of characters separated by `-`\n  dashes, where the slug cannot begin or end with a dash, and there\n  can never be two dashes in a row.\n- every character with a defined notion of case is lower-cased\n\nExample: `Slug \"this-is-an-article-slug\"`\n","title":"Slug","info":{"roles":[],"declType":"data","dataDeclType":"newtype","typeArguments":[]},"sourceSpan":{"start":[31,1],"name":"/Users/trh/Desktop/purescript-slug/src/Slug.purs","end":[31,27]}},{"kind":null,"children":[],"comments":"Create a `Slug` from a string. This will transform the input string\nto be a valid slug (if it is possible to do so) by separating words\nwith `-` dashes, ensuring the string does not begin or end with a\ndash, and ensuring there are never two dashes in a row.\n\nSlugs are usually created for article titles and other resources\nwhich need a human-readable resource name in a URL.\n\n```purescript\n> Slug.generate \"My article title!\"\n> Just (Slug \"my-article-title\")\n\n> Slug.generate \"¬¬¬{}¬¬¬\"\n> Nothing\n```\n","title":"generate","info":{"declType":"value","type":{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Prim"],"Function"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Prim"],"String"]}]},{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Data","Maybe"],"Maybe"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Slug"],"Slug"]}]}]}},"sourceSpan":{"start":[61,1],"name":"/Users/trh/Desktop/purescript-slug/src/Slug.purs","end":[61,33]}},{"kind":null,"children":[],"comments":"Parse a valid slug (as a string) into a `Slug`. This will fail if the\nstring is not a valid slug and does not provide the same behavior as\n`generate`.\n\n```purescript\n> Slug.parse \"my-article-title\"\n> Just (Slug \"my-article-title\")\n\n> Slug.parse \"My article\"\n> Nothing\n```\n","title":"parse","info":{"declType":"value","type":{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Prim"],"Function"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Prim"],"String"]}]},{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Data","Maybe"],"Maybe"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Slug"],"Slug"]}]}]}},"sourceSpan":{"start":[92,1],"name":"/Users/trh/Desktop/purescript-slug/src/Slug.purs","end":[92,30]}},{"kind":null,"children":[],"comments":"Unwrap a `Slug` into the string contained within, without performing\nany transformations.\n\n```purescript\n> Slug.toString (mySlug :: Slug)\n> \"my-slug-i-generated\"\n```\n","title":"toString","info":{"declType":"value","type":{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Prim"],"Function"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Slug"],"Slug"]}]},{"annotation":[],"tag":"TypeConstructor","contents":[["Prim"],"String"]}]}},"sourceSpan":{"start":[106,1],"name":"/Users/trh/Desktop/purescript-slug/src/Slug.purs","end":[106,27]}},{"kind":null,"children":[],"comments":"Ensure a `Slug` is no longer than a given number of characters. If the last\ncharacter is a dash, it will also be removed. Providing a non-positive\nnumber as the length will return `Nothing`.\n\n```purescript\n> Slug.create \"My article title is long!\" >>= Slug.truncate 3\n> Just (Slug \"my\")\n```\n","title":"truncate","info":{"declType":"value","type":{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Prim"],"Function"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Prim"],"Int"]}]},{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Prim"],"Function"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Slug"],"Slug"]}]},{"annotation":[],"tag":"TypeApp","contents":[{"annotation":[],"tag":"TypeConstructor","contents":[["Data","Maybe"],"Maybe"]},{"annotation":[],"tag":"TypeConstructor","contents":[["Slug"],"Slug"]}]}]}]}},"sourceSpan":{"start":[117,1],"name":"/Users/trh/Desktop/purescript-slug/src/Slug.purs","end":[117,38]}}]}],"resolvedDependencies":{},"version":"3.0.1","github":["thomashoneyman","purescript-slug"],"versionTag":"v3.0.1","moduleMap":{"Data.BooleanAlgebra":"purescript-prelude","Data.Decide":"purescript-contravariant","Type.Data.Boolean":"purescript-typelevel-prelude","Data.Ring":"purescript-prelude","Data.Semigroup.Generic":"purescript-prelude","Record.Unsafe.Union":"purescript-record","Data.Functor.Product":"purescript-functors","Type.Function":"purescript-typelevel-prelude","Data.Functor.Flip":"purescript-functors","Data.NonEmpty":"purescript-nonempty","Effect.Uncurried":"purescript-effect","Data.Char.Gen":"purescript-strings","Data.Monoid.Generic":"purescript-prelude","Data.String.NonEmpty":"purescript-strings","Effect":"purescript-effect","Data.Traversable.Accum.Internal":"purescript-foldable-traversable","Data.CodePoint.Unicode.Internal":"purescript-unicode","Data.Enum.Gen":"purescript-enums","Data.Functor.Costar":"purescript-functors","Data.HeytingAlgebra.Generic":"purescript-prelude","Data.Functor.Compose":"purescript-functors","Foreign.Object.Gen":"purescript-foreign-object","Type.Row.Homogeneous":"purescript-typelevel-prelude","Data.Int.Bits":"purescript-integers","Data.String.CodePoints":"purescript-strings","Data.Ord":"purescript-prelude","Control.Monad.Gen":"purescript-gen","Data.Bounded.Generic":"purescript-prelude","Type.Data.Row":"purescript-prelude","Data.Argonaut.Parser":"purescript-argonaut-core","Data.Argonaut.Encode.Combinators":"purescript-argonaut-codecs","Safe.Coerce":"purescript-safe-coerce","Data.Monoid.Dual":"purescript-prelude","Control.Monad.Rec.Class":"purescript-tailrec","Data.Bitraversable":"purescript-foldable-traversable","Record.Builder":"purescript-record","Data.Boolean":"purescript-prelude","Data.Show.Generic":"purescript-prelude","Data.Map":"purescript-ordered-collections","Control.Biapplicative":"purescript-bifunctors","Data.Array.NonEmpty.Internal":"purescript-arrays","Type.Proxy":"purescript-prelude","Data.String.Unicode":"purescript-unicode","Data.Array.ST.Iterator":"purescript-arrays","Data.Enum.Generic":"purescript-enums","Data.String.Pattern":"purescript-strings","Data.Bounded":"purescript-prelude","Data.TraversableWithIndex":"purescript-foldable-traversable","Data.Int":"purescript-integers","Data.Profunctor.Cochoice":"purescript-profunctor","Data.Show":"purescript-prelude","Data.Foldable":"purescript-foldable-traversable","Data.Divide":"purescript-contravariant","Data.Number":"purescript-numbers","Data.Enum":"purescript-enums","Foreign.Object":"purescript-foreign-object","Control.Apply":"purescript-prelude","Data.Functor.Contravariant":"purescript-contravariant","Data.Tuple.Nested":"purescript-tuples","Data.List.Internal":"purescript-lists","Control.Monad":"purescript-prelude","Data.Lazy":"purescript-lazy","Data.Monoid":"purescript-prelude","Data.Profunctor.Closed":"purescript-profunctor","Data.Ord.Generic":"purescript-prelude","Data.String.Common":"purescript-strings","Data.Maybe.First":"purescript-maybe","Control.Bind":"purescript-prelude","Data.Profunctor.Split":"purescript-profunctor","Data.Number.Format":"purescript-numbers","Data.CodePoint.Unicode.Internal.Casing":"purescript-unicode","Data.Monoid.Additive":"purescript-prelude","Data.Symbol":"purescript-prelude","Data.Map.Gen":"purescript-ordered-collections","Data.String.Regex":"purescript-strings","Data.Profunctor.Join":"purescript-profunctor","Data.HeytingAlgebra":"purescript-prelude","Control.Alt":"purescript-control","Control.Monad.ST.Internal":"purescript-st","Type.Data.RowList":"purescript-prelude","Effect.Ref":"purescript-refs","Data.Either.Inject":"purescript-either","Foreign.Object.ST.Unsafe":"purescript-foreign-object","Data.List.ZipList":"purescript-lists","Data.Ord.Min":"purescript-orders","Data.Functor.Coproduct.Nested":"purescript-functors","Data.Ring.Generic":"purescript-prelude","Data.Semigroup":"purescript-prelude","Data.Array.NonEmpty":"purescript-arrays","Data.Const":"purescript-const","Data.Argonaut.Encode.Class":"purescript-argonaut-codecs","Data.Ord.Down":"purescript-orders","Data.Number.Approximate":"purescript-numbers","Data.Array.ST.Partial":"purescript-arrays","Effect.Unsafe":"purescript-effect","Type.Data.Ordering":"purescript-typelevel-prelude","Data.Tuple":"purescript-tuples","Data.Functor.Clown":"purescript-functors","Data.Semigroup.Foldable":"purescript-foldable-traversable","Control.Biapply":"purescript-bifunctors","Data.Distributive":"purescript-distributive","Type.Equality":"purescript-type-equality","Control.Alternative":"purescript-control","Data.Semiring":"purescript-prelude","Data.Functor.Product2":"purescript-functors","Data.Exists":"purescript-exists","Data.CodePoint.Unicode":"purescript-unicode","Data.Traversable.Accum":"purescript-foldable-traversable","Data.CommutativeRing":"purescript-prelude","Data.NaturalTransformation":"purescript-prelude","Data.Monoid.Conj":"purescript-prelude","Data.Functor.App":"purescript-functors","Data.Profunctor.Star":"purescript-profunctor","Data.Unfoldable":"purescript-unfoldable","Type.RowList":"purescript-typelevel-prelude","Foreign.Object.Unsafe":"purescript-foreign-object","Control.Monad.ST":"purescript-st","Data.Argonaut.Decode":"purescript-argonaut-codecs","Data.List.Types":"purescript-lists","Data.String.NonEmpty.CodeUnits":"purescript-strings","Data.Functor":"purescript-prelude","Unsafe.Coerce":"purescript-unsafe-coerce","Data.Profunctor.Strong":"purescript-profunctor","Data.List.Lazy.Types":"purescript-lists","Control.Category":"purescript-prelude","Control.Monad.Gen.Common":"purescript-gen","Data.Maybe":"purescript-maybe","Type.Row":"purescript-typelevel-prelude","Data.String.Regex.Unsafe":"purescript-strings","Foreign.Object.ST":"purescript-foreign-object","Data.Set":"purescript-ordered-collections","Data.Profunctor":"purescript-profunctor","Control.Comonad":"purescript-control","Control.Monad.ST.Global":"purescript-st","Data.Function":"purescript-prelude","Data.List":"purescript-lists","Data.Field":"purescript-prelude","Data.List.Lazy":"purescript-lists","Data.EuclideanRing":"purescript-prelude","Data.Semigroup.Last":"purescript-prelude","Data.Semigroup.First":"purescript-prelude","Data.Functor.Invariant":"purescript-invariant","Data.Comparison":"purescript-contravariant","Data.String.Unsafe":"purescript-strings","Prelude":"purescript-prelude","Data.Argonaut.Decode.Error":"purescript-argonaut-codecs","Effect.Class":"purescript-effect","Data.Predicate":"purescript-contravariant","Partial.Unsafe":"purescript-partial","Data.Array":"purescript-arrays","Control.Extend":"purescript-control","Data.Unfoldable1":"purescript-unfoldable","Control.Lazy":"purescript-control","Data.Function.Uncurried":"purescript-functions","Data.Functor.Product.Nested":"purescript-functors","Data.Eq":"purescript-prelude","Data.Either.Nested":"purescript-either","Data.Newtype":"purescript-newtype","Data.Semigroup.Traversable":"purescript-foldable-traversable","Data.Bifunctor":"purescript-bifunctors","Data.Argonaut.Encode.Encoders":"purescript-argonaut-codecs","Data.Argonaut.Decode.Decoders":"purescript-argonaut-codecs","Data.Monoid.Disj":"purescript-prelude","Control.Monad.Gen.Class":"purescript-gen","Data.Array.Partial":"purescript-arrays","Data.String.CaseInsensitive":"purescript-strings","Control.MonadPlus":"purescript-control","Data.Void":"purescript-prelude","Control.MonadZero":"purescript-control","Data.Profunctor.Costrong":"purescript-profunctor","Data.Ord.Max":"purescript-orders","Data.String.CodeUnits":"purescript-strings","Data.FunctorWithIndex":"purescript-foldable-traversable","Data.Divisible":"purescript-contravariant","Data.Eq.Generic":"purescript-prelude","Data.DivisionRing":"purescript-prelude","Record":"purescript-record","Data.Equivalence":"purescript-contravariant","Data.Maybe.Last":"purescript-maybe","Data.Unit":"purescript-prelude","Data.Argonaut.Decode.Parser":"purescript-argonaut-codecs","Data.List.NonEmpty":"purescript-lists","Data.List.Lazy.NonEmpty":"purescript-lists","Data.Ordering":"purescript-prelude","Data.Functor.Coproduct":"purescript-functors","Data.Argonaut.Decode.Combinators":"purescript-argonaut-codecs","Data.Identity":"purescript-identity","Math":"purescript-math","Data.Set.NonEmpty":"purescript-ordered-collections","Data.String":"purescript-strings","Control.Plus":"purescript-control","Data.Argonaut.Encode":"purescript-argonaut-codecs","Data.Map.Internal":"purescript-ordered-collections","Partial":"purescript-partial","Data.String.NonEmpty.CodePoints":"purescript-strings","Data.Decidable":"purescript-contravariant","Data.String.NonEmpty.Internal":"purescript-strings","Data.Monoid.Multiplicative":"purescript-prelude","Data.String.NonEmpty.CaseInsensitive":"purescript-strings","Data.Functor.Joker":"purescript-functors","Type.Data.Symbol":"purescript-typelevel-prelude","Data.Array.ST":"purescript-arrays","Data.Argonaut.Core":"purescript-argonaut-core","Control.Semigroupoid":"purescript-prelude","Data.Monoid.Alternate":"purescript-control","Data.Char":"purescript-strings","Data.Generic.Rep":"purescript-prelude","Data.Bifunctor.Join":"purescript-bifunctors","Data.Bifoldable":"purescript-foldable-traversable","Control.Monad.ST.Ref":"purescript-st","Data.Monoid.Endo":"purescript-prelude","Data.List.Partial":"purescript-lists","Data.Semiring.Generic":"purescript-prelude","Data.String.Regex.Flags":"purescript-strings","Data.Argonaut.Decode.Class":"purescript-argonaut-codecs","Data.Either":"purescript-either","Type.Prelude":"purescript-typelevel-prelude","Control.Applicative":"purescript-prelude","Control.Monad.ST.Class":"purescript-st","Data.FoldableWithIndex":"purescript-foldable-traversable","Data.Op":"purescript-contravariant","Record.Unsafe":"purescript-prelude","Data.Argonaut.Gen":"purescript-argonaut-core","Data.Functor.Coproduct.Inject":"purescript-functors","Data.Profunctor.Choice":"purescript-profunctor","Data.Traversable":"purescript-foldable-traversable","Data.String.Gen":"purescript-strings"},"compilerVersion":"0.14.5"}

@thomashoneyman thomashoneyman requested a review from f-f February 24, 2022 03:04
@thomashoneyman
Copy link
Copy Markdown
Member Author

I was a little suspicious of the uploader field being null in the output, but the only time it's ever set in publish is here:

let pkgUploader = D.NotYetKnown

I haven't pieced together exactly when this field gets set or if it's a legacy thing; looks like it was placed there 7 years ago when psc-publish was moved into this repository.

@JordanMartinez
Copy link
Copy Markdown
Contributor

I followed your instructions and got a slightly different result.

$ git status
HEAD detached at v3.0.1
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	.purs.json

nothing added to commit but untracked files present (use "git add" to track)

$ ./../publish-test/purs publish --manifest .purs.json --resolutions ../resolutions.json 
There is a problem with your package, which meant that it could not be         
published.                                                                     
Details:                                                                       
  Your git working tree is dirty. Please commit, discard, or stash your changes
  first.

$ git add .purs.json

$ git commit -m "Added .purs.json"

$ ./../publish-test/purs publish --manifest .purs.json --resolutions ../resolutions.json 
There is a problem with your package, which meant that it could not be          
published.                                                                      
Details:                                                                        
  purs publish requires a tagged version to be checked out in order to build    
  documentation, and no suitable tag was found. Please check out a previously   
  tagged version, or tag a new version.                                         
                                                                                
  Note: tagged versions must be in the form                                     
    v{MAJOR}.{MINOR}.{PATCH} (example: "v1.6.2")                                
                                                                                
  If the version you are publishing is not yet tagged, you might want to use the
  --dry-run flag instead, which removes this requirement. Run `purs publish     
  --help` for more details. 

# Reran with the `--dry-run` flag
$ ./../publish-test/purs publish --manifest .purs.json --resolutions ../resolutions.json --dry-run
There is a problem with your package, which meant that it could not be                                                        
published.                                                                                                                    
Details:                                                                                                                      
  Compile error:                                                                                                              
    Error 1 of 10:                                                                                                            
      in module Slug                                                                                                 
      at /home/jordan/Programming/Projects/purescript-slug/src/Slug.purs:9:1 - 9:15 (line 9, column 1 - line 9, column 15)    
                                                                                                                              
        Module Prelude was not found.                                                                                
        Make sure the source file exists, and that it has been provided as an input to the compiler.                          
                                                                                                                              
                                                                                                                              
      See https://github.com/purescript/documentation/blob/master/errors/ModuleNotFound.md for more information,              
      or to contribute content related to this error. 
      
    ....

$ spago install

$ ./../publish-test/purs publish --manifest .purs.json --resolutions ../resolutions.json --dry-run
Compiling documentation for Unsafe.Coerce
Compiling documentation for Type.Proxy
Compiling documentation for Type.Function
....
Warnings:                                                                      
  The following packages did not appear to have a resolved version:            
    * purescript-newtype                                                       
    * purescript-effect                                                        
    * purescript-ordered-collections                                           
    * purescript-unicode                                                       
    * purescript-control                                                       
    * purescript-either                                                        
    * purescript-profunctor                                                    
    * purescript-arrays                                                        
    * purescript-maybe                                                         
    * purescript-type-equality                                                 
    * purescript-exists                                                        
    * purescript-distributive                                                  
    * purescript-unfoldable                                                    
    * purescript-invariant                                                     
    * purescript-argonaut-core                                                 
    * purescript-lazy                                                          
    * purescript-foreign-object                                                
    * purescript-foldable-traversable                                          
    * purescript-tailrec                                                       
    * purescript-gen                                                           
    * purescript-typelevel-prelude                                             
    * purescript-functors                                                      
    * purescript-prelude                                                       
    * purescript-st                                                            
    * purescript-bifunctors                                                    
    * purescript-nonempty                                                      
    * purescript-contravariant                                                 
    * purescript-unsafe-coerce                                                 
    * purescript-refs                                                          
    * purescript-integers                                                      
    * purescript-argonaut-codecs                                               
    * purescript-orders                                                        
    * purescript-const                                                         
    * purescript-record                                                        
    * purescript-numbers                                                       
    * purescript-math                                                          
    * purescript-enums                                                         
    * purescript-tuples                                                        
    * purescript-partial                                                       
    * purescript-strings                                                       
    * purescript-identity                                                      
    * purescript-safe-coerce                                                   
    * purescript-lists                                                         
    * purescript-functions                                                     
                                                                               
  Links to types in any of these packages will not work. In order to make links
  work, edit your package manifest to specify a version or a version range for 
  these packages.                                                              
Dry run completed, no errors.

@thomashoneyman thomashoneyman changed the title Support the .purs.json manifest in purs publish Support the purs.json manifest in purs publish Feb 24, 2022
@thomashoneyman
Copy link
Copy Markdown
Member Author

thomashoneyman commented Feb 24, 2022

That's odd. I tried to reproduce fresh, but failed:

purescript-slug on HEAD (6f54a98) [?] via <=> v0.14.5 
λ git status
HEAD detached at v3.0.1
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        purs.json

nothing added to commit but untracked files present (use "git add" to track)

λ /Users/trh/Desktop/purescript/.stack-work/install/x86_64-osx/e9764b3b76c5da9b4a7047f9b1cdc2f02cbd4ce8b8f8af670efb6f643827aab5/8.10.7/bin/purs publish --manifest purs.json --resolutions ../resolutions.json 
Warnings:                                                                      
  The following packages did not appear to have a resolved version:            
    * purescript-newtype                                                       
    * ...                                                                                                         
                                                                               
  Links to types in any of these packages will not work. In order to make links
  work, edit your package manifest to specify a version or a version range for 
  these packages.                                                              
{"uploader":null,"packageMeta": ... }

I did forget in the original instructions that you have to run spago install before publishing, otherwise the paths in the resolutions file will not exist. You definitely don't need to commit anything; you have to have the tag checked out that you're publishing, and you can't commit anything on top of it.

Is it possible that you had a stale purs you were testing with, @JordanMartinez?

@thomashoneyman
Copy link
Copy Markdown
Member Author

As a side note, those warnings about missing resolved versions are just because I didn't put specific versions in the resolutions file to save myself some time. In the real world we'd include those versions when generating the resolutions file and there would be no warnings -- that's not related to this PR.

@JordanMartinez
Copy link
Copy Markdown
Contributor

JordanMartinez commented Feb 24, 2022

Is it possible that you had a stale purs you were testing with, @JordanMartinez?

I ran stack purge because I had too many things built in the install directory, and then I ran stack build. However, I was doing stuff on the es-modules PR, so it's possible I had that checked out instead. I'll try again.

@JordanMartinez
Copy link
Copy Markdown
Contributor

Yup, looks like I was using a stale purs. This code works.

-- For the time being, we only parse manifests that include a GitHub owner
-- and repo pair, or which specify a Git URL, which we use to try and get
-- the package from GitHub.
pursJsonLocation <- key "location" (catchError asOwnerRepo (const asGitUrl))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I edited the purs.json file, so that the location.githubRepo field was deleted, I got this error:

There is a problem with your package, which meant that it could not be
published.                                                            
Details:                                                              
  There was a problem with your package manifest file:                
    At the path: ["location"]                                         
    The required key "gitUrl" is missing                              
                                                                      
  Please ensure that your package manifest file is valid.

Perhaps instead of const asGitUrl, we should report both errors? For example, something like "after failing to find the location.githubRepo field, tried to parse location as git url, but failed."

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, this is a good point. I'll put together a custom error for it.

@JordanMartinez
Copy link
Copy Markdown
Contributor

Changing the license field in purs.json to something nonsensical produces this error:

There is a problem with your package, which meant that it could not be       
published.                                                                   
Details:                                                                     
  The license specified in package manifest is not a valid SPDX license      
  expression. Please update the "license" property so that it is a valid SPDX
  license expression. For example, any of the following would be acceptable: 
                                                                             
    * "MIT"                                                                  
    * "Apache-2.0"                                                           
    * "BSD-2-Clause"                                                         
    * "GPL-2.0-or-later"                                                     
    * "(GPL-3.0-only OR MIT)"

IIRC, the Registry only supports one license, not expressions (e.g. AND, OR), correct? If so, then when the Registry is fully deployed and we're dropping support for Bower, we'll need to update this error message to remove the "OR" expression example.

@thomashoneyman
Copy link
Copy Markdown
Member Author

IIRC, the Registry only supports one license, not expressions (e.g. AND, OR), correct? If so, then when the Registry is fully deployed and we're dropping support for Bower, we'll need to update this error message to remove the "OR" expression example.

The registry supports SPDX license expressions, too, so this is a correct error.

@JordanMartinez
Copy link
Copy Markdown
Contributor

Changing the purs.json version field to 3.0.0 produces this abbreviated JSON:

{
  "version": "3.0.1",
  "versionTag": "v3.0.1",
}

If the version field isn't being used (as it seems the git tag is being used instead), should it be required in the purs.json file?

@thomashoneyman
Copy link
Copy Markdown
Member Author

thomashoneyman commented Feb 24, 2022

produces this abbreviated JSON:

Where are you seeing this?

If the version field isn't being used (as it seems the git tag is being used instead), should it be required in the purs.json file?

The git tag is only being used because that's how the existing publishing process works, but the registry does not use git tags to record versions (this would prevent monorepo setups). I don't actually need to parse the version field at all, and can defer only to the version tag.

Edit Sorry, I misread your comment. I thought you were seeing the 3.0.0 being picked up, but I see both versions are 3.0.1 as expected. I'll remove the version JSON parsing.

@JordanMartinez
Copy link
Copy Markdown
Contributor

I thought you were seeing the 3.0.0 being picked up, but I see both versions are 3.0.1 as expected. I'll remove the version JSON parsing.

On second thought, removing the version here means people will need to add it later when Bower support is dropped completely. What if we threw an error if the git tag does not match the version stated in the purs.json file?

In arguing for this approach, people would already be used to focusing on the version field when we drop Bower support and fully support the Manifest.dhall schema. In other words, before that breaking change occurs, people would be used to using git tags and the 'version' field. After that change occurs, people would only need to think about the version field. If we didn't do this, they'd focus on git tags before that breaking change and then focus on the version field after that breaking change.

In arguing against this, we would then need to handle cases like the git tag returning v1.2.3 and the version field containing 1.2.3 and reconciling the differences. Moreover, this check could actually be quite annoying.

So, perhaps dropping version is the best way forward.

@thomashoneyman
Copy link
Copy Markdown
Member Author

On second thought, removing the version here means people will need to add it later when Bower support is dropped completely.

The registry requires the version field, so the only question here is whether purs publish should additionally check for it in the manifest file. I don't think this is much of an issue -- package managers generate the purs.json file, and the registry requires it when publishing, so there's little risk here besides a user hand-writing a manifest file, leaving it untracked, and using it directly with purs publish without a package manager.

Moreover, this check could actually be quite annoying.

It certainly would 😆 this information would have to be threaded through into the preparePackage' function, because it's not part of the Bower PackageMeta type. We wouldn't be able to simply reuse the existing pipeline and would have to special-case this check. I certainly think we should add more verification of this kind in the future, but I think that should be part of an overhaul to purs publish to fully support the new manifests (not just this compatibility layer).

Copy link
Copy Markdown
Contributor

@JordanMartinez JordanMartinez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I'm guessing you'll want @f-f to review it, too, before it gets merged?

@thomashoneyman
Copy link
Copy Markdown
Member Author

It's not strictly necessary, so we can merge if it gets time to be 0.14.6, but I'd like him to take a look if possible.

@f-f
Copy link
Copy Markdown
Member

f-f commented Feb 24, 2022

I'll have a look tomorrow morning!

Copy link
Copy Markdown
Member

@f-f f-f left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, thanks @thomashoneyman!

@JordanMartinez JordanMartinez merged commit 7f385cd into master Feb 25, 2022
@JordanMartinez JordanMartinez deleted the trh/purs-publish branch February 25, 2022 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support the PureScript Registry manifest format in purs publish

3 participants