Skip to content
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

Not use the versions file for NPM tools #24

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

pete-murphy
Copy link

@pete-murphy pete-murphy commented Aug 10, 2021

Resolves: #23

I've tried to come up with the minimal change to make this work (if I'm understanding the intended behavior). These changes delay the interpretation of VersionFieldVersion until the installMethod is called. So resolve has been updated to return a VersionField instead of Version, and that VersionField is passed through getTool and finally to installMethod where, if it's Latest and the tool is an NPM tool, it is converted to the string "latest" (to generate, e.g., npm install purs-tidy@latest), otherwise it's converted to a version string via Version.showVersion. I'm not sure this is the best way of going about this (or if I've even correctly understood the intended logic), but no other ideas have come to my mind 😅 I'm very much open to suggestion.

@pete-murphy pete-murphy force-pushed the pm/not-use-the-versions-file-for-npm branch from e25c92c to a5436b3 Compare August 10, 2021 03:36
Comment on lines +54 to 57
resolve :: Json -> Tool -> ExceptT Error Effect (Maybe { tool :: Tool, versionField :: VersionField })
resolve versionsContents tool = do
let key = Key.fromTool tool
field <- getVersionField key
Copy link
Author

@pete-murphy pete-murphy Aug 10, 2021

Choose a reason for hiding this comment

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

😕 Don't feel good about this approach where I get a VersionField within this function, but then do some transformation of it before returning a conditionally-modified VersionField as output.

@pete-murphy pete-murphy force-pushed the pm/not-use-the-versions-file-for-npm branch from a5436b3 to 13fd320 Compare August 10, 2021 03:42
Comment on lines +1 to +12
module Setup.Data.VersionField (VersionField(..), showVersionField) where

import Data.Version (Version)
import Data.Version as Version

-- | The parsed value of an input field that specifies a version
data VersionField = Latest | Exact Version

showVersionField :: VersionField -> String
showVersionField = case _ of
Latest -> "latest"
Exact v -> Version.showVersion v
Copy link
Author

Choose a reason for hiding this comment

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

This module was just for avoiding circular dependencies.

@pete-murphy pete-murphy force-pushed the pm/not-use-the-versions-file-for-npm branch from 13fd320 to 2a448cc Compare August 10, 2021 03:44
Comment on lines 160 to +163
formatTag :: String
formatTag = do
let versionStr = Version.showVersion version
if tool `elem` [ PureScript, Zephyr, Psa ] then
let versionStr = VersionField.showVersionField versionField
if tool `elem` [ PureScript, Zephyr ] then
Copy link
Author

Choose a reason for hiding this comment

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

I think the Psa case here was unreachable—formatTag is only referenced in the PureScript, Spago and Zephyr cases. If it is needed, I would have to expand this a bit so not to prepend v to latest.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we should either:

  1. Inline formatTag so that it's obviously only used for the Tarball installation method, because that's the only time we need to bother with the specific format of the tag, or
  2. Keep Psa in here, and add PursTidy, because they do use a v prefix on their tags (unlike, for example, how Spago formats tags with no v prefix).

My preference would be (1) because we really don't need the tag for the NPM install method.

Comment on lines -121 to +138
if version >= unsafeVersion "0.18.1" then case platform of
Windows -> "Windows"
Mac -> "macOS"
Linux -> "Linux"
else if version == unsafeVersion "0.18.0" then case platform of
Windows -> "windows-latest"
Mac -> "macOS-latest"
Linux -> "linux-latest"
else case platform of
Windows -> "windows"
Mac -> "osx"
Linux -> "linux"
case versionField of
Exact version
| version >= unsafeVersion "0.18.1" ->
case platform of
Windows -> "Windows"
Mac -> "macOS"
Linux -> "Linux"
| version == unsafeVersion "0.18.1" ->
case platform of
Windows -> "windows-latest"
Mac -> "macOS-latest"
Linux -> "linux-latest"
_ ->
case platform of
Windows -> "windows"
Mac -> "osx"
Linux -> "linux"
Copy link
Author

Choose a reason for hiding this comment

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

In this Spago case, we know we've got an Exact version for versionField, but that's not represented in the types, so end up having to have a wildcard case. Struggling with how to "make impossible states unrepresentable" here...

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yea, I think this is a sign that we haven't got the data structures quite right -- this feels awkward. Ideally, by the time we know we're installing a tarball we also know that we must have an exact version ready to go.

Comment on lines +52 to +53
-- | on the action.yml file. In the case of NPM packages, bypass the action.yml
-- | file and use 'Latest'.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This isn't quite right -- we don't want to bypass the action.yml because that's where the user specifies "latest" or a specific version. If they give a specific version then we want to use that. It's rather that we want to bypass the versions file when the user wants the 'latest' version of an NPM-installed package.


-- | Construct the list of tools that sholud be downloaded and cached by the action
constructBuildPlan :: Json -> ExceptT Error Effect BuildPlan
constructBuildPlan json = map Array.catMaybes $ traverse (resolve json) Tool.allTools

-- | The parsed value of an input field that specifies a version
data VersionField = Latest | Exact Version

-- | Attempt to read the value of an input specifying a tool version
getVersionField :: Key -> ExceptT Error Effect (Maybe VersionField)
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we move VersionField out to its own module, then I think we ought to move this function to that module as well.


-- | Construct the list of tools that sholud be downloaded and cached by the action
constructBuildPlan :: Json -> ExceptT Error Effect BuildPlan
constructBuildPlan json = map Array.catMaybes $ traverse (resolve json) Tool.allTools

-- | The parsed value of an input field that specifies a version
data VersionField = Latest | Exact Version

-- | Attempt to read the value of an input specifying a 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.

We should expand this documentation comment, because I had to re-read the implementation!

Suggested change
-- | Attempt to read the value of an input specifying a tool version
-- | Attempt to read the value of an input specifying a tool version. If the input is missing
-- | and is not required, then we return `Nothing`. If the input is present and the user has
-- | specified an exact version or the latest version then we return the parsed `VersionField`.

resolve :: Json -> Tool -> ExceptT Error Effect (Maybe { tool :: Tool, version :: Version })
-- | on the action.yml file. In the case of NPM packages, bypass the action.yml
-- | file and use 'Latest'.
resolve :: Json -> Tool -> ExceptT Error Effect (Maybe { tool :: Tool, versionField :: VersionField })
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if this functionality should just be baked into the installMethod function so that there are fewer cases to admit? After all, that's the place where we know explicitly whether a tool is NPM-installed or not.


liftEffect $ Core.info $ fold [ "Fetching ", name ]

case installMethod of
Tarball opts -> do
mbPath <- mapExceptT liftEffect $ ToolCache.find { arch: Nothing, toolName: name, versionSpec: Version.showVersion version }
mbPath <- mapExceptT liftEffect $ ToolCache.find { arch: Nothing, toolName: name, versionSpec: VersionField.showVersionField versionField }
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 bit long, so perhaps we could import VersionField as VF?

@thomashoneyman
Copy link
Collaborator

@ptrfrncsmrph I think this is a nice start! It looks like you're understanding everything correctly. I think we might have to shuffle things around a bit more so that we read the versions file close to where we determine the install method, just so that there are fewer places where we're plumbing through a VersionField that we're going to manipulate later.

We might even need to change a data type like InstallMethod so that it includes an exact version for tarballs (which we resolve from the versions file) and either Latest or Exact versions for NPM-installed tools (which we don't resolve from the versions file).

@pete-murphy
Copy link
Author

Thanks for the feedback! I should be able to give it another pass and re-request review in the next couple days

@pete-murphy
Copy link
Author

Sorry for delay, I've tried starting over with this, but still not satisfied with the result. What I've got so far: main...ptrfrncsmrph:pm/issue-23-attempt-use-string-as-version. There I'm just passing around the version as a String (which could be literal "latest" or the result of Version.showVersion), which gets awkward when needing to check if that string is greater than or equal to "0.18.0", e.g.

We might even need to change a data type like InstallMethod so that it includes an exact version for tarballs (which we resolve from the versions file) and either Latest or Exact versions for NPM-installed tools (which we don't resolve from the versions file).

Trying to think through how this would work: would the installMethod function be merged into resolve so we have something like

resolve :: Json -> Tool -> ExceptT Error Effect (Maybe InstallMethod)

I've started doing something like that here, but resolve ends up being pretty massive and complex and I might be getting off on the wrong foot: main...ptrfrncsmrph:pm/issue-23-attempt-refactor-install-method.

@pete-murphy pete-murphy marked this pull request as draft September 5, 2021 03:09
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.

Don't use the versions file for tools installed via NPM
2 participants