-
-
Notifications
You must be signed in to change notification settings - Fork 75
/
Copy pathUpdate.hs
724 lines (635 loc) · 24.1 KB
/
Update.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
module Update
( addPatched,
assertNotUpdatedOn,
cveAll,
cveReport,
prMessage,
sourceGithubAll,
updatePackage,
)
where
import CVE (CVE, cveID, cveLI)
import qualified Check
import Control.Exception (bracket)
import Control.Monad.Writer (execWriterT, tell)
import Data.Maybe (fromJust)
import Data.Monoid (Alt (..))
import qualified Data.Set as S
import qualified Data.Text as T
import qualified Data.Text.IO as T
import Data.Time.Calendar (showGregorian)
import Data.Time.Clock (getCurrentTime, utctDay)
import qualified GH
import qualified Git
import NVD (getCVEs, withVulnDB)
import qualified Nix
import qualified NixpkgsReview
import OurPrelude
import qualified Outpaths
import qualified Rewrite
import qualified Skiplist
import System.Directory (doesDirectoryExist, withCurrentDirectory)
import System.Posix.Directory (createDirectory)
import Utils
( Boundary (..),
Options (..),
UpdateEnv (..),
VersionMatcher (..),
branchName,
logDir,
parseUpdates,
prTitle,
whenBatch,
)
import qualified Utils as U
import qualified Version
import Prelude hiding (log)
default (T.Text)
alsoLogToAttrPath :: Text -> (Text -> IO ()) -> IO (Text -> IO ())
alsoLogToAttrPath attrPath topLevelLog = do
logFile <- attrPathLogFilePath attrPath
let attrPathLog = log' logFile
return \text -> do
topLevelLog text
attrPathLog text
log' :: MonadIO m => FilePath -> Text -> m ()
log' logFile msg = liftIO $ T.appendFile logFile (msg <> "\n")
attrPathLogFilePath :: Text -> IO String
attrPathLogFilePath attrPath = do
lDir <- logDir
now <- getCurrentTime
let dir = lDir <> "/" <> T.unpack attrPath
dirExists <- doesDirectoryExist dir
unless
dirExists
(createDirectory dir U.regDirMode)
let logFile = dir <> "/" <> showGregorian (utctDay now) <> ".log"
putStrLn ("For attrpath " <> T.unpack attrPath <> ", using log file: " <> logFile)
return logFile
notifyOptions :: (Text -> IO ()) -> Options -> IO ()
notifyOptions log o = do
let repr f = if f o then "YES" else "NO"
let ghUser = GH.untagName . githubUser $ o
let pr = repr doPR
let batch = repr batchUpdate
let outpaths = repr calculateOutpaths
let cve = repr makeCVEReport
let review = repr runNixpkgsReview
let exactAttrPath = repr U.attrpath
npDir <- tshow <$> Git.nixpkgsDir
log $
[interpolate| [options] github_user: $ghUser, pull_request: $pr, batch_update: $batch, calculate_outpaths: $outpaths, cve_report: $cve, nixpkgs-review: $review, nixpkgs_dir: $npDir, use attrpath: $exactAttrPath|]
cveAll :: Options -> Text -> IO ()
cveAll o updates = do
let u' = rights $ parseUpdates updates
results <-
mapM
( \(p, oldV, newV, url) -> do
r <- cveReport (UpdateEnv p oldV newV url o)
return $ p <> ": " <> oldV <> " -> " <> newV <> "\n" <> r
)
u'
T.putStrLn (T.unlines results)
sourceGithubAll :: Options -> Text -> IO ()
sourceGithubAll o updates = do
let u' = rights $ parseUpdates updates
_ <-
runExceptT $ do
Git.fetchIfStale <|> liftIO (T.putStrLn "Failed to fetch.")
Git.cleanAndResetTo "master"
mapM_
( \(p, oldV, newV, url) -> do
let updateEnv = UpdateEnv p oldV newV url o
runExceptT $ do
attrPath <- Nix.lookupAttrPath updateEnv
srcUrl <- Nix.getSrcUrl attrPath
v <- GH.latestVersion updateEnv srcUrl
if v /= newV
then
liftIO $
T.putStrLn $
p <> ": " <> oldV <> " -> " <> newV <> " -> " <> v
else return ()
)
u'
data UpdatePackageResult = UpdatePackageSuccess | UpdatePackageFailure
-- Arguments this function should have to make it testable:
-- - the merge base commit (should be updated externally to this function)
-- - the commit for branches: master, staging, staging-next
updatePackageBatch ::
(Text -> IO ()) ->
Text ->
UpdateEnv ->
IO UpdatePackageResult
updatePackageBatch simpleLog updateInfoLine updateEnv@UpdateEnv {..} = do
eitherFailureOrAttrpath <- runExceptT $ do
-- Filters that don't need git
whenBatch updateEnv do
Skiplist.packageName packageName
-- Update our git checkout
Git.fetchIfStale <|> liftIO (T.putStrLn "Failed to fetch.")
-- Filters: various cases where we shouldn't update the package
if attrpath options
then return packageName
else Nix.lookupAttrPath updateEnv
case eitherFailureOrAttrpath of
Left failure -> do
simpleLog failure
return UpdatePackageFailure
Right foundAttrPath -> do
log <- alsoLogToAttrPath foundAttrPath simpleLog
log updateInfoLine
mergeBase <-
if batchUpdate options
then Git.mergeBase
else pure "HEAD"
withWorktree mergeBase foundAttrPath updateEnv $
updateAttrPath log mergeBase updateEnv foundAttrPath
checkExistingUpdate ::
(Text -> IO ()) ->
UpdateEnv ->
Maybe Text ->
Text ->
ExceptT Text IO ()
checkExistingUpdate log updateEnv existingCommitMsg attrPath = do
case existingCommitMsg of
Nothing -> lift $ log "No auto update branch exists"
Just msg -> do
let nV = newVersion updateEnv
lift $
log
[interpolate|An auto update branch exists with message `$msg`. New version is $nV.|]
case U.titleVersion msg of
Just branchV
| Version.matchVersion (RangeMatcher (Including nV) Unbounded) branchV ->
throwError "An auto update branch exists with an equal or greater version"
_ ->
lift $ log "The auto update branch does not match or exceed the new version."
-- Note that this check looks for PRs with the same old and new
-- version numbers, so it won't stop us from updating an existing PR
-- if this run updates the package to a newer version.
GH.checkExistingUpdatePR updateEnv attrPath
updateAttrPath ::
(Text -> IO ()) ->
Text ->
UpdateEnv ->
Text ->
IO UpdatePackageResult
updateAttrPath log mergeBase updateEnv@UpdateEnv {..} attrPath = do
log $ "attrpath: " <> attrPath
let pr = doPR options
successOrFailure <- runExceptT $ do
hasUpdateScript <- Nix.hasUpdateScript attrPath
existingCommitMsg <- fmap getAlt . execWriterT $
whenBatch updateEnv do
Skiplist.attrPath attrPath
when pr do
liftIO $ log "Checking auto update branch..."
mbLastCommitMsg <- lift $ Git.findAutoUpdateBranchMessage packageName
tell $ Alt mbLastCommitMsg
unless hasUpdateScript do
lift $ checkExistingUpdate log updateEnv mbLastCommitMsg attrPath
unless hasUpdateScript do
Nix.assertNewerVersion updateEnv
Version.assertCompatibleWithPathPin updateEnv attrPath
let skipOutpathBase = either Just (const Nothing) $ Skiplist.skipOutpathCalc packageName
derivationFile <- Nix.getDerivationFile attrPath
unless hasUpdateScript do
assertNotUpdatedOn updateEnv derivationFile "master"
assertNotUpdatedOn updateEnv derivationFile "staging"
assertNotUpdatedOn updateEnv derivationFile "staging-next"
-- Calculate output paths for rebuilds and our merge base
let calcOutpaths = calculateOutpaths options && isNothing skipOutpathBase
mergeBaseOutpathSet <-
if calcOutpaths
then Outpaths.currentOutpathSet
else return $ Outpaths.dummyOutpathSetBefore attrPath
-- Get the original values for diffing purposes
derivationContents <- liftIO $ T.readFile $ T.unpack derivationFile
oldHash <- Nix.getHash attrPath <|> pure ""
oldSrcUrl <- Nix.getSrcUrl attrPath <|> pure ""
oldRev <- Nix.getAttrString "rev" attrPath <|> pure ""
oldVerMay <- rightMay `fmapRT` (lift $ runExceptT $ Nix.getAttrString "version" attrPath)
tryAssert
"The derivation has no 'version' attribute, so do not know how to figure out the version while doing an updateScript update"
(not hasUpdateScript || isJust oldVerMay)
-- One final filter
Skiplist.content derivationContents
----------------------------------------------------------------------------
-- UPDATES
--
-- At this point, we've stashed the old derivation contents and
-- validated that we actually should be rewriting something. Get
-- to work processing the various rewrite functions!
rewriteMsgs <- Rewrite.runAll log Rewrite.Args {derivationFile = T.unpack derivationFile, ..}
----------------------------------------------------------------------------
-- Compute the diff and get updated values
diffAfterRewrites <- Git.diff mergeBase
tryAssert
"The diff was empty after rewrites."
(diffAfterRewrites /= T.empty)
lift . log $ "Diff after rewrites:\n" <> diffAfterRewrites
updatedDerivationContents <- liftIO $ T.readFile $ T.unpack derivationFile
newSrcUrl <- Nix.getSrcUrl attrPath <|> pure ""
newHash <- Nix.getHash attrPath <|> pure ""
newRev <- Nix.getAttrString "rev" attrPath <|> pure ""
newVerMay <- rightMay `fmapRT` (lift $ runExceptT $ Nix.getAttrString "version" attrPath)
tryAssert
"The derivation has no 'version' attribute, so do not know how to figure out the version while doing an updateScript update"
(not hasUpdateScript || isJust newVerMay)
-- Sanity checks to make sure the PR is worth opening
unless hasUpdateScript do
when (derivationContents == updatedDerivationContents) $ throwE "No rewrites performed on derivation."
when (oldSrcUrl /= "" && oldSrcUrl == newSrcUrl) $ throwE "Source url did not change. "
when (oldHash /= "" && oldHash == newHash) $ throwE "Hashes equal; no update necessary"
when (oldRev /= "" && oldRev == newRev) $ throwE "rev equal; no update necessary"
--
-- Update updateEnv if using updateScript
updateEnv' <-
if hasUpdateScript
then do
-- Already checked that these are Just above.
let oldVer = fromJust oldVerMay
let newVer = fromJust newVerMay
-- Some update scripts make file changes but don't update the package
-- version; ignore these updates (#388)
when (newVer == oldVer) $ throwE "Package version did not change."
return $
UpdateEnv
packageName
oldVer
newVer
(Just "passthru.updateScript")
options
else return updateEnv
whenBatch updateEnv do
when pr do
when hasUpdateScript do
checkExistingUpdate log updateEnv' existingCommitMsg attrPath
when hasUpdateScript do
changedFiles <- Git.diffFileNames mergeBase
let rewrittenFile = case changedFiles of [f] -> f; _ -> derivationFile
assertNotUpdatedOn updateEnv' rewrittenFile "master"
assertNotUpdatedOn updateEnv' rewrittenFile "staging"
assertNotUpdatedOn updateEnv' rewrittenFile "staging-next"
--
-- Outpaths
-- this sections is very slow
editedOutpathSet <- if calcOutpaths then Outpaths.currentOutpathSetUncached else return $ Outpaths.dummyOutpathSetAfter attrPath
let opDiff = S.difference mergeBaseOutpathSet editedOutpathSet
let numPRebuilds = Outpaths.numPackageRebuilds opDiff
whenBatch updateEnv do
Skiplist.python numPRebuilds derivationContents
when (numPRebuilds == 0) (throwE "Update edits cause no rebuilds.")
-- end outpaths section
Nix.build attrPath
--
-- Publish the result
lift . log $ "Successfully finished processing"
result <- Nix.resultLink
let opReport =
if isJust skipOutpathBase
then "Outpath calculations were skipped for this package; total number of rebuilds unknown."
else Outpaths.outpathReport opDiff
let prBase =
flip
fromMaybe
skipOutpathBase
if Outpaths.numPackageRebuilds opDiff <= 500
then "master"
else "staging"
publishPackage log updateEnv' oldSrcUrl newSrcUrl attrPath result opReport prBase rewriteMsgs (isJust existingCommitMsg)
case successOrFailure of
Left failure -> do
log failure
return UpdatePackageFailure
Right () -> return UpdatePackageSuccess
publishPackage ::
(Text -> IO ()) ->
UpdateEnv ->
Text ->
Text ->
Text ->
Text ->
Text ->
Text ->
[Text] ->
Bool ->
ExceptT Text IO ()
publishPackage log updateEnv oldSrcUrl newSrcUrl attrPath result opReport prBase rewriteMsgs branchExists = do
cacheTestInstructions <- doCache log updateEnv result
resultCheckReport <-
case Skiplist.checkResult (packageName updateEnv) of
Right () -> lift $ Check.result updateEnv (T.unpack result)
Left msg -> pure msg
metaDescription <- Nix.getDescription attrPath <|> return T.empty
metaHomepage <- Nix.getHomepage attrPath <|> return T.empty
metaChangelog <- Nix.getChangelog attrPath <|> return T.empty
cveRep <- liftIO $ cveReport updateEnv
releaseUrl <- GH.releaseUrl updateEnv newSrcUrl <|> return ""
compareUrl <- GH.compareUrl oldSrcUrl newSrcUrl <|> return ""
maintainers <- Nix.getMaintainers attrPath
let commitMsg = commitMessage updateEnv attrPath
Git.commit commitMsg
commitRev <- Git.headRev
nixpkgsReviewMsg <-
if prBase /= "staging" && (runNixpkgsReview . options $ updateEnv)
then liftIO $ NixpkgsReview.runReport log commitRev
else return ""
isBroken <- Nix.getIsBroken attrPath
-- Try to push it three times
-- (these pushes use --force, so it doesn't matter if branchExists is True)
when
(doPR . options $ updateEnv)
(Git.push updateEnv <|> Git.push updateEnv <|> Git.push updateEnv)
let prMsg =
prMessage
updateEnv
isBroken
metaDescription
metaHomepage
metaChangelog
rewriteMsgs
releaseUrl
compareUrl
resultCheckReport
commitRev
attrPath
maintainers
result
opReport
cveRep
cacheTestInstructions
nixpkgsReviewMsg
liftIO $ log prMsg
if (doPR . options $ updateEnv)
then do
let ghUser = GH.untagName . githubUser . options $ updateEnv
let mkPR = if branchExists then GH.prUpdate else GH.pr
(reusedPR, pullRequestUrl) <- mkPR updateEnv (prTitle updateEnv attrPath) prMsg (ghUser <> ":" <> (branchName updateEnv)) prBase
when branchExists $
liftIO $
log
if reusedPR
then "Updated existing PR"
else "Reused existing auto update branch, but no corresponding open PR was found, so created a new PR"
liftIO $ log pullRequestUrl
else liftIO $ T.putStrLn prMsg
commitMessage :: UpdateEnv -> Text -> Text
commitMessage updateEnv attrPath = prTitle updateEnv attrPath
brokenWarning :: Bool -> Text
brokenWarning False = ""
brokenWarning True =
"- WARNING: Package has meta.broken=true; Please manually test this package update and remove the broken attribute."
prMessage ::
UpdateEnv ->
Bool ->
Text ->
Text ->
Text ->
[Text] ->
Text ->
Text ->
Text ->
Text ->
Text ->
Text ->
Text ->
Text ->
Text ->
Text ->
Text ->
Text
prMessage updateEnv isBroken metaDescription metaHomepage metaChangelog rewriteMsgs releaseUrl compareUrl resultCheckReport commitRev attrPath maintainers resultPath opReport cveRep cacheTestInstructions nixpkgsReviewMsg =
-- Some components of the PR description are pre-generated prior to calling
-- because they require IO, but in general try to put as much as possible for
-- the formatting into the pure function so that we can control the body
-- formatting in one place and unit test it.
let brokenMsg = brokenWarning isBroken
metaHomepageLine =
if metaHomepage == T.empty
then ""
else "meta.homepage for " <> attrPath <> " is: " <> metaHomepage
metaDescriptionLine =
if metaDescription == T.empty
then ""
else "meta.description for " <> attrPath <> " is: " <> metaDescription
metaChangelogLine =
if metaChangelog == T.empty
then ""
else "meta.changelog for " <> attrPath <> " is: " <> metaChangelog
rewriteMsgsLine = foldl (\ms m -> ms <> T.pack "\n- " <> m) "\n###### Updates performed" rewriteMsgs
maintainersCc =
if not (T.null maintainers)
then "cc " <> maintainers <> " for [testing](https://github.com/ryantm/nixpkgs-update/blob/main/doc/nixpkgs-maintainer-faq.md#r-ryantm-opened-a-pr-for-my-package-what-do-i-do)."
else ""
releaseUrlMessage =
if releaseUrl == T.empty
then ""
else "- [Release on GitHub](" <> releaseUrl <> ")"
compareUrlMessage =
if compareUrl == T.empty
then ""
else "- [Compare changes on GitHub](" <> compareUrl <> ")"
nixpkgsReviewSection =
if nixpkgsReviewMsg == T.empty
then "NixPkgs review skipped"
else
[interpolate|
We have automatically built all packages that will get rebuilt due to
this change.
This gives evidence on whether the upgrade will break dependent packages.
Note sometimes packages show up as _failed to build_ independent of the
change, simply because they are already broken on the target branch.
$nixpkgsReviewMsg
|]
pat link = [interpolate|This update was made based on information from $link.|]
sourceLinkInfo = maybe "" pat $ sourceURL updateEnv
ghUser = GH.untagName . githubUser . options $ updateEnv
batch = batchUpdate . options $ updateEnv
automatic = if batch then "Automatic" else "Semi-automatic"
in [interpolate|
$automatic update generated by [nixpkgs-update](https://github.com/ryantm/nixpkgs-update) tools. $sourceLinkInfo
$brokenMsg
$metaDescriptionLine
$metaHomepageLine
$metaChangelogLine
$rewriteMsgsLine
###### To inspect upstream changes
$releaseUrlMessage
$compareUrlMessage
###### Impact
<b>Checks done</b>
---
- built on NixOS
$resultCheckReport
---
<details>
<summary>
<b>Rebuild report</b> (if merged into master) (click to expand)
</summary>
```
$opReport
```
</details>
<details>
<summary>
<b>Instructions to test this update</b> (click to expand)
</summary>
---
$cacheTestInstructions
```
nix-build -A $attrPath https://github.com/$ghUser/nixpkgs/archive/$commitRev.tar.gz
```
Or:
```
nix build github:$ghUser/nixpkgs/$commitRev#$attrPath
```
After you've downloaded or built it, look at the files and if there are any, run the binaries:
```
ls -la $resultPath
ls -la $resultPath/bin
```
---
</details>
<br/>
$cveRep
### Pre-merge build results
$nixpkgsReviewSection
---
###### Maintainer pings
$maintainersCc
> [!TIP]
> As a maintainer, if your package is located under `pkgs/by-name/*`, you can comment **`@NixOS/nixpkgs-merge-bot merge`** to automatically merge this update using the [`nixpkgs-merge-bot`](https://github.com/NixOS/nixpkgs-merge-bot).
---
Add a :+1: [reaction] to [pull requests you find important].
[reaction]: https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/
[pull requests you find important]: https://github.com/NixOS/nixpkgs/pulls?q=is%3Aopen+sort%3Areactions-%2B1-desc
|]
assertNotUpdatedOn ::
MonadIO m => UpdateEnv -> Text -> Text -> ExceptT Text m ()
assertNotUpdatedOn updateEnv derivationFile branch = do
derivationContents <- Git.show branch derivationFile
Nix.assertOldVersionOn updateEnv branch derivationContents
addPatched :: Text -> Set CVE -> IO [(CVE, Bool)]
addPatched attrPath set = do
let list = S.toList set
forM
list
( \cve -> do
patched <- runExceptT $ Nix.hasPatchNamed attrPath (cveID cve)
let p =
case patched of
Left _ -> False
Right r -> r
return (cve, p)
)
cveReport :: UpdateEnv -> IO Text
cveReport updateEnv =
if not (makeCVEReport . options $ updateEnv)
then return ""
else withVulnDB $ \conn -> do
let pname1 = packageName updateEnv
let pname2 = T.replace "-" "_" pname1
oldCVEs1 <- getCVEs conn pname1 (oldVersion updateEnv)
oldCVEs2 <- getCVEs conn pname2 (oldVersion updateEnv)
let oldCVEs = S.fromList (oldCVEs1 ++ oldCVEs2)
newCVEs1 <- getCVEs conn pname1 (newVersion updateEnv)
newCVEs2 <- getCVEs conn pname2 (newVersion updateEnv)
let newCVEs = S.fromList (newCVEs1 ++ newCVEs2)
let inOldButNotNew = S.difference oldCVEs newCVEs
inNewButNotOld = S.difference newCVEs oldCVEs
inBoth = S.intersection oldCVEs newCVEs
ifEmptyNone t =
if t == T.empty
then "none"
else t
inOldButNotNew' <- addPatched (packageName updateEnv) inOldButNotNew
inNewButNotOld' <- addPatched (packageName updateEnv) inNewButNotOld
inBoth' <- addPatched (packageName updateEnv) inBoth
let toMkdownList = fmap (uncurry cveLI) >>> T.unlines >>> ifEmptyNone
fixedList = toMkdownList inOldButNotNew'
newList = toMkdownList inNewButNotOld'
unresolvedList = toMkdownList inBoth'
if fixedList == "none" && unresolvedList == "none" && newList == "none"
then return ""
else
return
[interpolate|
###### Security vulnerability report
<details>
<summary>
Security report (click to expand)
</summary>
CVEs resolved by this update:
$fixedList
CVEs introduced by this update:
$newList
CVEs present in both versions:
$unresolvedList
</details>
<br/>
|]
doCache :: MonadIO m => (Text -> m ()) -> UpdateEnv -> Text -> ExceptT Text m Text
doCache log updateEnv resultPath =
let o = options updateEnv
in if batchUpdate o && "r-ryantm" == (GH.untagName $ githubUser o)
then do
return
[interpolate|
Either **download from the cache**:
```
nix-store -r $resultPath \
--option binary-caches 'https://cache.nixos.org/ https://nixpkgs-update-cache.nix-community.org/' \
--option trusted-public-keys '
nixpkgs-update-cache.nix-community.org-1:U8d6wiQecHUPJFSqHN9GSSmNkmdiFW7GW7WNAnHW0SM=
cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
'
```
(The nixpkgs-update cache is only trusted for this store-path realization.)
For the cached download to work, your user must be in the `trusted-users` list or you can use `sudo` since root is effectively trusted.
Or, **build yourself**:
|]
else do
lift $ log "skipping cache"
return "Build yourself:"
updatePackage ::
Options ->
Text ->
IO ()
updatePackage o updateInfo = do
let (p, oldV, newV, url) = head (rights (parseUpdates updateInfo))
let updateInfoLine = (p <> " " <> oldV <> " -> " <> newV <> fromMaybe "" (fmap (" " <>) url))
let updateEnv = UpdateEnv p oldV newV url o
let log = T.putStrLn
liftIO $ notifyOptions log o
updated <- updatePackageBatch log updateInfoLine updateEnv
case updated of
UpdatePackageFailure -> do
log $ "[result] Failed to update " <> updateInfoLine
UpdatePackageSuccess -> do
log $ "[result] Success updating " <> updateInfoLine
withWorktree :: Text -> Text -> UpdateEnv -> IO a -> IO a
withWorktree branch attrpath updateEnv action = do
bracket
( do
dir <- U.worktreeDir
let path = dir <> "/" <> T.unpack (T.replace ".lock" "_lock" attrpath)
Git.worktreeRemove path
Git.delete1 (branchName updateEnv)
Git.worktreeAdd path branch updateEnv
pure path
)
( \path -> do
Git.worktreeRemove path
Git.delete1 (branchName updateEnv)
)
(\path -> withCurrentDirectory path action)