Skip to content

Support pre-release versions for PureScript tool #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
Mar 1, 2022

Conversation

JordanMartinez
Copy link
Contributor

Fixes #26 using the below syntax

steps:
  - uses: actions/checkout@v2
  - uses: purescript-contrib/setup-purescript@main
    with:
      purescript: "unstable-0.15.0"

Similar to using latest as the version string, the code will find the most recent pre-release version whose version matches the one used in the string. So unstable-0.15.0 or unstable-v0.15.0 would drop the unstable- prefix and parse the 0.15.0 part as its corresponding Version value. Using the Version value, we search for the first pre-release version that has the same version (albeit different pre-release or build metadata). Thus, unstable-0.15.0 would match 0.15.0-rc.1, 0.15.0-rc.2, or 0.15.0-rc.3, etc.. Moreover, unstable-0.15.1 would not find 0.15.0-rc.1 or vice versa.

In the event there are multiple pre-releases, we use whichever one was published most recently. GitHub's API returns the most recent releases first, so we don't have to do any additional sorting. If this ever changes, we'd need to update the code.

Using this API URL: https://api.github.com/repos/purescript/purescript/releases?per_page=10&page=1 the releases at the given index prove this ordering:

  • index 6: v0.14.0
  • index 7: v0.14.0-rc.5
  • index 8: v0.14.0-rc.4
  • index 9: v0.14.0-rc.3

@thomashoneyman
Copy link
Collaborator

@JordanMartinez Thanks for putting this together!

I don't think we need this amount of flexibility around the unstable option; I would prefer that unstable simply refers to the very latest version of the compiler, regardless of whether it is an rc or not. The same way that latest lets you get the latest (stable) version of the compiler, but you can't say "latest-0.15.1", unstable would get you the latest version of the compiler including release candidates.

If we want to let you opt in to the latest in a particular series or something then we should probably support SemVer ranges rather than come up with our own scheme.

@JordanMartinez
Copy link
Contributor Author

Ok, I'll update this PR to do that.

@JordanMartinez
Copy link
Contributor Author

unstable now works exactly like latest (across all tools, not just PureScript) except that pre-releases are included.

@thomashoneyman
Copy link
Collaborator

I can’t give this a good review until later today, but at a glance it looks good to me.

Comment on lines 92 to 95
liftEffect do
Core.info $ fold [ "Fetching most recent version (pre-release or not) for ", Tool.name tool ]
version <- liftAff $ fetchFromGitHubReleases AnyRelease (Tool.repository tool)
pure (pure { tool, version })
Copy link
Collaborator

Choose a reason for hiding this comment

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

Usually we read the latest tag from the stored versions.json file:
https://github.com/purescript-contrib/setup-purescript/blob/main/dist/versions.json

We do this because it's really easy to burn requests to the GitHub API and these versions don't change that frequently. You can see this in practice in the Latest case right above this, where we read the file.

I think we might want to update the format of this file to something like:

{
  "purs": { "stable": ..., "unstable": ... },
  ...
}

and then we can read either the latest stable or unstable version depending on what the user wants. Note that if we ever want to update to the latest unstable version faster than the daily check this repo does, we can always manually update the versions.json file right away.

Copy link
Collaborator

Choose a reason for hiding this comment

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

(At this point it would probably help to have an actual type and JSON encoding / decoding, rather than the inline thing we've got going now)

Copy link
Contributor Author

@JordanMartinez JordanMartinez Feb 28, 2022

Choose a reason for hiding this comment

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

I keep trying to write this but then run into friction over the design of this project. Could you clarify why Tool and Key are separate things?

Copy link
Collaborator

Choose a reason for hiding this comment

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

The difference is a little annoying, and we probably should have just used the executable name for everything. But the reason it exists is that there can be a difference between the name of a tool (PureScript) and the name of the executable (purs).

Other than that, the only difference between Tool and Key is that the tool is a data type and the key is a string, the actual thing the user types into their action.yml file.

@thomashoneyman
Copy link
Collaborator

We also need to update the README to acknowledge this is a possible version to specify:

https://github.com/purescript-contrib/setup-purescript#specify-versions

@JordanMartinez
Copy link
Contributor Author

JordanMartinez commented Mar 1, 2022

So... I ran node update.js locally and it never terminated. I'm assuming that's a bug in my code?

Edit: it did terminate but it took a long time.

@JordanMartinez
Copy link
Contributor Author

CI is failing because it's attempting to read master's versions.json file rather than the updated one I pushed here.

Perhaps we should add an env check to use the PR's versions.json file if we detect we're in CI?

@JordanMartinez
Copy link
Contributor Author

CI now builds.

@JordanMartinez
Copy link
Contributor Author

Per a call with Thomas, the following issues were pointed out.

First, while most of contrib libraries use setup-purescript@main, the problem is other libraries may be using setup-purescript@someVersion. The compiled code always checks the main branch's versions.json file to see what the latest version is. By migrating the schema to something else, such libraries' CI will fail.

One could ask, "Why wasn't this repo released, such that the versions file is frozen to prevent such migration issues?" Freezing the file like that would prevent the latest version field from working. Either one would have to call GitHub's API to get that info every time CI ran, which could lead to rate limiting, or one can read the versions.json file and use less requests. So, reading the main branch's versions.json file is actually necessary for the "latest version" feature.

Second, to workaround this design constraint, we can provide different versions of the versions.json file. For example, the versions.json file will remain untouched. But we can create a versions-v2.json that does use the schema proposed here (i.e. purs: { latest: ..., unstable: ... }. By using two separate files, we enable the following workflow:

  • updating the versions.json will update all versions.json files, such that the "latest version" feature still works regardless of which version of setup-purescript CI is using
  • for the current main branch, only read from the latest versions.json file (i.e. versions-v2.json for this PR)
  • if we need to support new versions or change the schema again, we can create a new file (e.g. versions-v3.json) and the old code will still function correctly.

Third, since this new design touches a couple of things, we'll want to implement it in a single module to keep everything together.

Note: this PR still updates purs to v0.14.7
@JordanMartinez
Copy link
Contributor Author

@thomashoneyman I haven't tested this locally, but this is the design I went with. I can walk you through this via a call if that would help, but I'll try to summarize things below.

I put the version files in src/Setup/Data/VersionFiles.purs. latestVersion should point to the latest one, so that way it's easier to verify that we're updating every usage of it. Perhaps you want even more code moved into VersionFiles.purs, but I thought this was a good start to see if my approach is good.

In the codecs, I decided not to reuse things like Tool.name because I'm not sure if we would want to change that in the future or not (e.g. add new cases, etc.). So, the codecs should continue to work despite whatever changes we make to the Tool type.

README.md Outdated
Each tool can accept one of the following:
- a semantic version (only exact versions currently supported)
- the string `"latest"`, which represents the latest non-prerelease version
- the string `"unstable"`, which represents the latest version (pre-release or not)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Perhaps we can specify that:

  • "latest" will bring in the latest version that uses major, minor, and patch, but it will omit versions using build metadata or prerelease identifiers
  • "unstable" will bring in the latest version no matter what it is (ie. build metadata and prerelease identifiers are accepted)

Comment on lines 121 to 122
-- in case we add support for other tools in the future...
toolToMbString = case _ of
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe just printTool for the name, and update the comment to say something like:

-- We preserve the set of tools that existed at the time this version format was produced;
-- if more tools are added, they should map to `Nothing`

Just versions' -> do
let
unstable = firstUnstableVersion <|> Array.head versions'
latest = Array.find (not <<< Version.isPreRelease) versions'
Copy link
Collaborator

Choose a reason for hiding this comment

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

This really ought to check for build metadata, too. We can check that the Version.buildMetadata list is empty.

https://github.com/hdgarrood/purescript-versions/blob/9799321bfa516b05d68bea8da7b706219e87edd8/src/Data/Version.purs#L85-L86

Comment on lines +162 to +164
pure
if isDraft then Nothing
else Just version
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a little clunky (I know it's not your code) -- mind updating it to use guard?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried, but either implementation of guard doesn't work.

src/Setup/UpdateVersions.purs:165:23

  165                        guard isDraft
                             ^^^^^^^^^^^^^
  
  No type class instance was found for
  
    Control.Alternative.Alternative Aff
  
  while applying a function guard
    of type Alternative t2 => Boolean -> t2 Unit
    to argument isDraft
  while checking that expression guard isDraft
    has type t0 t1
  in value declaration toolVersions

and

src/Setup/UpdateVersions.purs:165:23

  165                        guard isDraft version
                             ^^^^^^^^^^^^^^^^^^^^^
  
  Could not match type
  
    Version
  
  with type
  
    t0 (Maybe t3)

or

src/Setup/UpdateVersions.purs:165:23

  165                        guard isDraft $ Just version
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  Could not match type
  
    Version
  
  with type
  
    Maybe t3

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, the ol' guardA. No worries, we can leave it as-is.

@thomashoneyman
Copy link
Collaborator

This looks good enough for me! With my comments addressed we can move forward. Thanks!

@JordanMartinez
Copy link
Contributor Author

Also, did you want to update your PureScript version in Nix? Looks like you're on v0.14.3 right now.

@thomashoneyman
Copy link
Collaborator

If you don't mind, it would be great to update! Thanks!

@JordanMartinez JordanMartinez merged commit 05b797a into main Mar 1, 2022
@JordanMartinez JordanMartinez deleted the support-pre-release-versions branch March 1, 2022 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Add ability to depend on latest PureScript release candidate via "unstable" version
2 participants