on master help sign in
Move the bump logic into terminal/ and get it close to working
commit7d402d6f209d98e2cd5d44ff9e840f36eaeaded5 authorEvan Czaplicki <evancz@users.noreply.github.com> dateTue 4 Jun 2019, 11:18 (7 years ago) parent7d06451
3 files changed+244−181
builder/src/Elm/Bump.hs−137 builder/src/Reporting/Exit.hs+74−36 terminal/src/Bump.hs+170−8
builder/src/Elm/Bump.hsdeleted−137
@@ -1,137 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−module Elm.Bump
3− ( bump
4− , toPossibleBumps
5− )
6− where
7−
8−
9−import Control.Monad.Trans (liftIO)
10−import qualified Data.List as List
11−
12−import qualified Deps.Cache as Cache
13−import qualified Deps.Diff as Diff
14−import qualified Elm.Project.Json as Project
15−import qualified Elm.Project.Summary as Summary
16−import qualified Elm.Version as V
17−import Reporting.Doc ((<>), (<+>))
18−import qualified Reporting.Doc as D
19−import qualified Reporting.Exit as Exit
20−import qualified Reporting.Exit.Bump as E
21−import qualified Reporting.Exit.Help as Help
22−import qualified Reporting.Progress.Terminal as Terminal
23−import qualified Reporting.Task as Task
24−
25−
26−
27−-- BUMP
28−
29−
30−bump :: Summary.Summary -> Task.Task ()
31−bump summary@(Summary.Summary root project _ _ _) =
32− case project of
33− Project.App _ ->
34− Task.throw (Exit.Bump E.Application)
35−
36− Project.Pkg info@(Project.PkgInfo name _ _ version _ _ _ _) ->
37− do registry <- Cache.mandatoryUpdate
38− case Cache.getVersions name registry of
39− Left _suggestions ->
40− checkNewPackage root info
41−
42− Right publishedVersions ->
43− let
44− bumpableVersions =
45− map (\(old, _, _) -> old) (toPossibleBumps publishedVersions)
46− in
47− if elem version bumpableVersions then
48− suggestVersion summary info
49− else
50− Task.throw $ Exit.Bump $ E.Unbumpable version $
51− map head (List.group (List.sort bumpableVersions))
52−
53−
54−
55−-- VALID BUMPS
56−
57−
58−toPossibleBumps :: [V.Version] -> [(V.Version, V.Version, Diff.Magnitude)]
59−toPossibleBumps publishedVersions =
60− case publishedVersions of
61− [] ->
62− []
63−
64− _ ->
65− let
66− patchPoints =
67− V.filterLatest V.majorAndMinor publishedVersions
68−
69− minorPoints =
70− V.filterLatest V._major publishedVersions
71−
72− majorPoint =
73− maximum publishedVersions
74− in
75− (majorPoint, V.bumpMajor majorPoint, Diff.MAJOR)
76− : map (\v -> (v, V.bumpMinor v, Diff.MINOR)) minorPoints
77− ++ map (\v -> (v, V.bumpPatch v, Diff.PATCH)) patchPoints
78−
79−
80−
81−-- CHECK NEW PACKAGE
82−
83−
84−checkNewPackage :: FilePath -> Project.PkgInfo -> Task.Task ()
85−checkNewPackage root info@(Project.PkgInfo _ _ _ version _ _ _ _) =
86− do liftIO $ putStrLn Terminal.newPackageOverview
87− if version == V.one
88− then
89− liftIO $ putStrLn "The version number in elm.json is correct so you are all set!"
90− else
91− changeVersion root info V.one $
92− "It looks like the version in elm.json has been changed though!\n\
93− \Would you like me to change it back to "
94− <> D.fromUtf8 (V.toString V.one) <> "? [Y/n] "
95−
96−
97−
98−-- SUGGEST VERSION
99−
100−
101−suggestVersion :: Summary.Summary -> Project.PkgInfo -> Task.Task ()
102−suggestVersion (Summary.Summary root _ _ _ _) info@(Project.PkgInfo name _ _ version _ _ _ _) =
103− do oldDocs <- Cache.getDocs name version
104− newDocs <- Task.silently (error "TODO Project.generateDocs summary")
105− let changes = Diff.diff oldDocs newDocs
106− let newVersion = Diff.bump changes version
107− changeVersion root info newVersion $
108− let
109− old = D.fromUtf8 $ V.toString version
110− new = D.fromUtf8 $ V.toString newVersion
111− mag = D.fromChars $ Diff.magnitudeToString (Diff.toMagnitude changes)
112− in
113− "Based on your new API, this should be a" <+> D.green mag <+> "change (" <> old <> " => " <> new <> ")\n"
114− <> "Bail out of this command and run 'elm diff' for a full explanation.\n"
115− <> "\n"
116− <> "Should I perform the update (" <> old <> " => " <> new <> ") in elm.json? [Y/n] "
117−
118−
119−
120−-- CHANGE VERSION
121−
122−
123−changeVersion :: FilePath -> Project.PkgInfo -> V.Version -> D.Doc -> Task.Task ()
124−changeVersion root info targetVersion explanation =
125− do approved <- Task.getApproval explanation
126− if not approved
127− then
128− liftIO $ putStrLn "Okay, I did not change anything!"
129−
130− else
131− do liftIO $ Project.write root $ Project.Pkg $
132− info { Project._pkg_version = targetVersion }
133−
134− liftIO $ Help.toStdout $
135− "Version changed to "
136− <> D.green (D.fromUtf8 (V.toString targetVersion))
137− <> "!\n"
builder/src/Reporting/Exit.hs+74−36
@@ -8,6 +8,10 @@ module Reporting.Exit
88 , Diff(..)
99 , diffToReport
1010 --
11+ , Bump(..)
12+ , bumpToReport
13+ , newPackageOverview
14+ --
1115 , Install(..)
1216 , installToReport
1317 --
@@ -60,13 +64,8 @@ import qualified Reporting.Error as Error
6064
6165
6266data Exit
63− -- bump
64− = BumpApplication
65− | BumpUnexpectedVersion V.Version [V.Version]
66− | BumpMustHaveLatestRegistry RegistryProblem
67− | BumpCannotFindDocs Pkg.Name V.Version DocsProblem
6867 -- publish
69− | PublishMustHaveLatestRegistry RegistryProblem
68+ = PublishMustHaveLatestRegistry RegistryProblem
7069 | PublishApplication
7170 | PublishNotInitialVersion V.Version
7271 | PublishAlreadyPublished V.Version
@@ -218,6 +217,75 @@ diffToReport diff =
218217
219218
220219
220+-- BUMP
221+
222+
223+data Bump
224+ = BumpNoOutline
225+ | BumpBadOutline Outline
226+ | BumpApplication
227+ | BumpUnexpectedVersion V.Version [V.Version]
228+ | BumpMustHaveLatestRegistry RegistryProblem
229+ | BumpCannotFindDocs Pkg.Name V.Version DocsProblem
230+
231+
232+bumpToReport :: Bump -> Help.Report
233+bumpToReport bump =
234+ case bump of
235+ BumpApplication ->
236+ Help.report "CANNOT BUMP APPLICATIONS" (Just "elm.json")
237+ "Your elm.json says this is an application. That means it cannot be published\
238+ \ on <https://package.elm-lang.org> and therefore has no version to bump!"
239+ []
240+
241+ BumpUnexpectedVersion vsn versions ->
242+ Help.docReport "CANNOT BUMP" (Just "elm.json")
243+ ( D.fillSep
244+ ["Your","elm.json","says","I","should","bump","relative","to","version"
245+ ,D.red (D.fromVersion vsn) <> ","
246+ ,"but","I","cannot","find","that","version","on","<https://package.elm-lang.org>."
247+ ,"That","means","there","is","no","API","for","me","to","diff","against","and"
248+ ,"figure","out","if","these","are","MAJOR,","MINOR,","or","PATCH","changes."
249+ ]
250+ )
251+ [ D.fillSep $
252+ ["Try","bumping","again","after","changing","the",D.dullyellow "\"version\"","in","elm.json"]
253+ ++ if length versions == 1 then ["to:"] else ["to","one","of","these:"]
254+ , D.vcat $ map (D.green . D.fromVersion) versions
255+ ]
256+
257+ BumpMustHaveLatestRegistry problem ->
258+ error "TODO BumpMustHaveLatestRegistry" problem
259+
260+ BumpCannotFindDocs name version problem ->
261+ error "TODO BumpCannotFindDocs" name version problem
262+
263+
264+
265+-- OVERVIEW OF VERSIONING
266+
267+
268+newPackageOverview :: String
269+newPackageOverview =
270+ unlines
271+ [ "This package has never been published before. Here's how things work:"
272+ , ""
273+ , " - Versions all have exactly three parts: MAJOR.MINOR.PATCH"
274+ , ""
275+ , " - All packages start with initial version " ++ V.toChars V.one
276+ , ""
277+ , " - Versions are incremented based on how the API changes:"
278+ , ""
279+ , " PATCH = the API is the same, no risk of breaking code"
280+ , " MINOR = values have been added, existing values are unchanged"
281+ , " MAJOR = existing values have been changed or removed"
282+ , ""
283+ , " - I will bump versions for you, automatically enforcing these rules"
284+ , ""
285+ ]
286+
287+
288+
221289-- INSTALL
222290
223291
@@ -429,36 +497,6 @@ _toReport :: Exit -> Help.Report
429497_toReport exit =
430498 case exit of
431499
432− -- bump
433−
434− BumpApplication ->
435− Help.report "CANNOT BUMP APPLICATIONS" (Just "elm.json")
436− "Your elm.json says this is an application. That means it cannot be published\
437− \ on <https://package.elm-lang.org> and therefore has no version to bump!"
438− []
439−
440− BumpUnexpectedVersion vsn versions ->
441− Help.docReport "CANNOT BUMP" (Just "elm.json")
442− ( D.fillSep
443− ["Your","elm.json","says","I","should","bump","relative","to","version"
444− ,D.red (D.fromVersion vsn) <> ","
445− ,"but","I","cannot","find","that","version","on","<https://package.elm-lang.org>."
446− ,"That","means","there","is","no","API","for","me","to","diff","against","and"
447− ,"figure","out","if","these","are","MAJOR,","MINOR,","or","PATCH","changes."
448− ]
449− )
450− [ D.fillSep $
451− ["Try","bumping","again","after","changing","the",D.dullyellow "\"version\"","in","elm.json"]
452− ++ if length versions == 1 then ["to:"] else ["to","one","of","these:"]
453− , D.vcat $ map (D.green . D.fromVersion) versions
454− ]
455−
456− BumpMustHaveLatestRegistry problem ->
457− error "TODO BumpMustHaveLatestRegistry" problem
458−
459− BumpCannotFindDocs name version problem ->
460− error "TODO BumpCannotFindDocs" name version problem
461−
462500 -- publish
463501
464502 PublishMustHaveLatestRegistry problem ->
terminal/src/Bump.hs+170−8
@@ -1,10 +1,27 @@
1−module Bump (run) where
1+{-# LANGUAGE OverloadedStrings #-}
2+module Bump
3+ ( run
4+ , toPossibleBumps
5+ )
6+ where
27
38
4−import qualified Elm.Bump as Bump
5−import qualified Elm.Project as Project
9+import qualified Data.List as List
10+
11+import qualified Deps.Diff as Diff
12+import qualified Deps.Registry as Registry
13+import qualified Elm.Details as Details
14+import qualified Elm.Magnitude as M
15+import qualified Elm.Outline as Outline
16+import qualified Elm.Version as V
17+import qualified Http
18+import Reporting.Doc ((<>), (<+>))
19+import qualified Reporting
20+import qualified Reporting.Doc as D
21+import qualified Reporting.Exit as Exit
22+import qualified Reporting.Exit.Help as Help
623import qualified Reporting.Task as Task
7−import qualified Reporting.Progress.Terminal as Terminal
24+import qualified Stuff
825
926
1027
@@ -13,7 +30,152 @@ import qualified Reporting.Progress.Terminal as Terminal
1330
1431run :: () -> () -> IO ()
1532run () () =
16− do reporter <- Terminal.create
17− Task.run reporter $
18− do summary <- Project.getRoot
19− Bump.bump summary
33+ Reporting.attempt Exit.bumpToReport $
34+ Task.run (bump =<< getEnv)
35+
36+
37+
38+-- ENV
39+
40+
41+data Env =
42+ Env
43+ { _root :: FilePath
44+ , _cache :: Stuff.PackageCache
45+ , _manager :: Http.Manager
46+ , _registry :: Registry.Registry
47+ , _outline :: Outline.Outline
48+ }
49+
50+
51+getEnv :: Task.Task Exit.Bump Env
52+getEnv =
53+ do maybeRoot <- Task.io $ Stuff.findRoot
54+ case maybeRoot of
55+ Nothing ->
56+ Task.throw Exit.BumpNoOutline
57+
58+ Just root ->
59+ do cache <- Task.io $ Stuff.getPackageCache
60+ manager <- Task.io $ Http.getManager
61+ registry <- Task.eio Exit.BumpMustHaveLatestRegistry $ Registry.latest manager cache
62+ outlineResult <- Task.io $ Outline.read root
63+ case outlineResult of
64+ Right outline ->
65+ return $ Env root cache manager registry outline
66+
67+ Left problem ->
68+ Task.throw $ Exit.BumpBadOutline problem
69+
70+
71+
72+-- BUMP
73+
74+
75+bump :: Env -> Task.Task Exit.Bump ()
76+bump env@(Env root _ _ registry outline) =
77+ case outline of
78+ Outline.App _ ->
79+ Task.throw Exit.BumpApplication
80+
81+ Outline.Pkg pkgOutline@(Outline.PkgOutline pkg _ _ vsn _ _ _ _) ->
82+ case Registry.getVersions pkg registry of
83+ Just knownVersions ->
84+ let
85+ bumpableVersions =
86+ map (\(old, _, _) -> old) (toPossibleBumps knownVersions)
87+ in
88+ if elem vsn bumpableVersions
89+ then suggestVersion env pkgOutline
90+ else
91+ Task.throw $ Exit.BumpUnexpectedVersion vsn $
92+ map head (List.group (List.sort bumpableVersions))
93+
94+ Nothing ->
95+ Task.io $ checkNewPackage root pkgOutline
96+
97+
98+
99+-- VALID BUMPS
100+
101+
102+toPossibleBumps :: Registry.KnownVersions -> [(V.Version, V.Version, M.Magnitude)]
103+toPossibleBumps (Registry.KnownVersions latest previous) =
104+ let
105+ allVersions = reverse (latest:previous)
106+ minorPoints = map last (List.groupBy sameMajor allVersions)
107+ patchPoints = map last (List.groupBy sameMinor allVersions)
108+ in
109+ (latest, V.bumpMajor latest, M.MAJOR)
110+ : map (\v -> (v, V.bumpMinor v, M.MINOR)) minorPoints
111+ ++ map (\v -> (v, V.bumpPatch v, M.PATCH)) patchPoints
112+
113+
114+sameMajor :: V.Version -> V.Version -> Bool
115+sameMajor (V.Version major1 _ _) (V.Version major2 _ _) =
116+ major1 == major2
117+
118+
119+sameMinor :: V.Version -> V.Version -> Bool
120+sameMinor (V.Version major1 minor1 _) (V.Version major2 minor2 _) =
121+ major1 == major2 && minor1 == minor2
122+
123+
124+
125+-- CHECK NEW PACKAGE
126+
127+
128+checkNewPackage :: FilePath -> Outline.PkgOutline -> IO ()
129+checkNewPackage root outline@(Outline.PkgOutline _ _ _ version _ _ _ _) =
130+ do putStrLn Exit.newPackageOverview
131+ if version == V.one
132+ then
133+ putStrLn "The version number in elm.json is correct so you are all set!"
134+ else
135+ changeVersion root outline V.one $
136+ "It looks like the version in elm.json has been changed though!\n\
137+ \Would you like me to change it back to "
138+ <> D.fromVersion V.one <> "? [Y/n] "
139+
140+
141+
142+-- SUGGEST VERSION
143+
144+
145+suggestVersion :: Env -> Outline.PkgOutline -> Task.Task Exit.Bump ()
146+suggestVersion (Env root cache manager _ _) outline@(Outline.PkgOutline pkg _ _ vsn _ _ _ _) =
147+ do oldDocs <- Task.eio (Exit.BumpCannotFindDocs pkg vsn) (Diff.getDocs cache manager pkg vsn)
148+ newDocs <- error "TODO Outline.generateDocs summary"
149+ let changes = Diff.diff oldDocs newDocs
150+ let newVersion = Diff.bump changes vsn
151+ Task.io $ changeVersion root outline newVersion $
152+ let
153+ old = D.fromVersion vsn
154+ new = D.fromVersion newVersion
155+ mag = D.fromChars $ M.toChars (Diff.toMagnitude changes)
156+ in
157+ "Based on your new API, this should be a" <+> D.green mag <+> "change (" <> old <> " => " <> new <> ")\n"
158+ <> "Bail out of this command and run 'elm diff' for a full explanation.\n"
159+ <> "\n"
160+ <> "Should I perform the update (" <> old <> " => " <> new <> ") in elm.json? [Y/n] "
161+
162+
163+
164+-- CHANGE VERSION
165+
166+
167+changeVersion :: FilePath -> Outline.PkgOutline -> V.Version -> D.Doc -> IO ()
168+changeVersion root outline targetVersion question =
169+ do approved <- Reporting.ask question
170+ if not approved
171+ then
172+ putStrLn "Okay, I did not change anything!"
173+
174+ else
175+ do Outline.write root $ Outline.Pkg $
176+ outline { Outline._pkg_version = targetVersion }
177+
178+ Help.toStdout $
179+ "Version changed to "
180+ <> D.green (D.fromVersion targetVersion)
181+ <> "!\n"