Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • project/automatic_updates
  • issue/automatic_updates-3159719
  • issue/automatic_updates-3227923
  • issue/automatic_updates-3227927
  • issue/automatic_updates-3227122
  • issue/automatic_updates-3227940
  • issue/automatic_updates-3228095
  • issue/automatic_updates-3228101
  • issue/automatic_updates-3228115
  • issue/automatic_updates-3228125
  • issue/automatic_updates-3228359
  • issue/automatic_updates-3228392
  • issue/automatic_updates-3225753
  • issue/automatic_updates-3227588
  • issue/automatic_updates-3228521
  • issue/automatic_updates-3228539
  • issue/automatic_updates-3226570
  • issue/automatic_updates-3228806
  • issue/automatic_updates-3227575
  • issue/automatic_updates-3229485
  • issue/automatic_updates-3228955
  • issue/automatic_updates-3230024
  • issue/automatic_updates-3230250
  • issue/automatic_updates-3230249
  • issue/automatic_updates-3230264
  • issue/automatic_updates-3230510
  • issue/automatic_updates-3230235
  • issue/automatic_updates-3230050
  • issue/automatic_updates-3230934
  • issue/automatic_updates-3230049
  • issue/automatic_updates-3230507
  • issue/automatic_updates-3231153
  • issue/automatic_updates-3231992
  • issue/automatic_updates-3232003
  • issue/automatic_updates-3232004
  • issue/automatic_updates-3231996
  • issue/automatic_updates-3231999
  • issue/automatic_updates-3230668
  • issue/automatic_updates-3232000
  • issue/automatic_updates-3232420
  • issue/automatic_updates-3232729
  • issue/automatic_updates-3232761
  • issue/automatic_updates-3231997
  • issue/automatic_updates-3232927
  • issue/automatic_updates-3232959
  • issue/automatic_updates-3233124
  • issue/automatic_updates-3230856
  • issue/automatic_updates-3233493
  • issue/automatic_updates-3233587
  • issue/automatic_updates-3233521
  • issue/automatic_updates-3236405
  • issue/automatic_updates-3236299
  • issue/automatic_updates-3238586
  • issue/automatic_updates-3238647
  • issue/automatic_updates-3238717
  • issue/automatic_updates-3238846
  • issue/automatic_updates-3238852
  • issue/automatic_updates-3238866
  • issue/automatic_updates-3238714
  • issue/automatic_updates-3239103
  • issue/automatic_updates-3233138
  • issue/automatic_updates-3239466
  • issue/automatic_updates-3239645
  • issue/automatic_updates-3239673
  • issue/automatic_updates-3277775
  • issue/automatic_updates-3280923
  • issue/automatic_updates-3275315
  • issue/automatic_updates-3279527
  • issue/automatic_updates-3279733
  • issue/automatic_updates-3281405
  • issue/automatic_updates-3281397
  • issue/automatic_updates-3280204
  • issue/automatic_updates-3277817
  • issue/automatic_updates-3277230
  • issue/automatic_updates-3276534
  • issue/automatic_updates-3279538
  • issue/automatic_updates-3280168
  • issue/automatic_updates-3271502
  • issue/automatic_updates-3283644
  • issue/automatic_updates-3302524
  • issue/automatic_updates-3275883
  • issue/automatic_updates-3280180
  • issue/automatic_updates-3274837
  • issue/automatic_updates-3281473
  • issue/automatic_updates-3281634
  • issue/automatic_updates-3239889
  • issue/automatic_updates-3240753
  • issue/automatic_updates-3233103
  • issue/automatic_updates-3240971
  • issue/automatic_updates-3233564
  • issue/automatic_updates-3241380
  • issue/automatic_updates-3241105
  • issue/automatic_updates-3242626
  • issue/automatic_updates-3242724
  • issue/automatic_updates-3243057
  • issue/automatic_updates-3243348
  • issue/automatic_updates-3243339
  • issue/automatic_updates-3243422
  • issue/automatic_updates-3243436
  • issue/automatic_updates-3243600
  • issue/automatic_updates-3243851
  • issue/automatic_updates-3243405
  • issue/automatic_updates-3244338
  • issue/automatic_updates-3244337
  • issue/automatic_updates-3244360
  • issue/automatic_updates-3244358
  • issue/automatic_updates-3244679
  • issue/automatic_updates-3244939
  • issue/automatic_updates-3244976
  • issue/automatic_updates-3245376
  • issue/automatic_updates-3245388
  • issue/automatic_updates-3245428
  • issue/automatic_updates-3245655
  • issue/automatic_updates-3245766
  • issue/automatic_updates-3245810
  • issue/automatic_updates-3245846
  • issue/automatic_updates-3246036
  • issue/automatic_updates-3246194
  • issue/automatic_updates-3246203
  • issue/automatic_updates-3246283
  • issue/automatic_updates-3279064
  • issue/automatic_updates-3246420
  • issue/automatic_updates-3246638
  • issue/automatic_updates-3246660
  • issue/automatic_updates-3246673
  • issue/automatic_updates-3246695
  • issue/automatic_updates-3245996
  • issue/automatic_updates-3247308
  • issue/automatic_updates-3247478
  • issue/automatic_updates-3247479
  • issue/automatic_updates-3279086
  • issue/automatic_updates-3248312
  • issue/automatic_updates-3248523
  • issue/automatic_updates-3248527
  • issue/automatic_updates-3244412
  • issue/automatic_updates-3248976
  • issue/automatic_updates-3248909
  • issue/automatic_updates-3246507
  • issue/automatic_updates-3249531
  • issue/automatic_updates-3249517
  • issue/automatic_updates-3249983
  • issue/automatic_updates-3249135
  • issue/automatic_updates-3250136
  • issue/automatic_updates-3250386
  • issue/automatic_updates-3251701
  • issue/automatic_updates-3250696
  • issue/automatic_updates-3248911
  • issue/automatic_updates-3227420
  • issue/automatic_updates-3252071
  • issue/automatic_updates-3252097
  • issue/automatic_updates-3252109
  • issue/automatic_updates-3252126
  • issue/automatic_updates-3249130
  • issue/automatic_updates-3251972
  • issue/automatic_updates-3252187
  • issue/automatic_updates-3252328
  • issue/automatic_updates-3252324
  • issue/automatic_updates-3252533
  • issue/automatic_updates-3253055
  • issue/automatic_updates-3253186
  • issue/automatic_updates-3253395
  • issue/automatic_updates-3253400
  • issue/automatic_updates-3253624
  • issue/automatic_updates-3253647
  • issue/automatic_updates-3253649
  • issue/automatic_updates-3253858
  • issue/automatic_updates-3254166
  • issue/automatic_updates-3254207
  • issue/automatic_updates-3279108
  • issue/automatic_updates-3254606
  • issue/automatic_updates-3254616
  • issue/automatic_updates-3254911
  • issue/automatic_updates-3255011
  • issue/automatic_updates-3255014
  • issue/automatic_updates-3255320
  • issue/automatic_updates-3277562
  • issue/automatic_updates-3255678
  • issue/automatic_updates-3256958
  • issue/automatic_updates-3257115
  • issue/automatic_updates-3257432
  • issue/automatic_updates-3257446
  • issue/automatic_updates-3257473
  • issue/automatic_updates-3257134
  • issue/automatic_updates-3257849
  • issue/automatic_updates-3258065
  • issue/automatic_updates-3258056
  • issue/automatic_updates-3258048
  • issue/automatic_updates-3258045
  • issue/automatic_updates-3258464
  • issue/automatic_updates-3258611
  • issue/automatic_updates-3258646
  • issue/automatic_updates-3258661
  • issue/automatic_updates-3258667
  • issue/automatic_updates-3258590
  • issue/automatic_updates-3259228
  • issue/automatic_updates-3259656
  • issue/automatic_updates-3252299
  • issue/automatic_updates-3259664
  • issue/automatic_updates-3259822
  • issue/automatic_updates-3259810
  • issue/automatic_updates-3259814
  • issue/automatic_updates-3260368
  • issue/automatic_updates-3257845
  • issue/automatic_updates-3260664
  • issue/automatic_updates-3260672
  • issue/automatic_updates-3260698
  • issue/automatic_updates-3260662
  • issue/automatic_updates-3260669
  • issue/automatic_updates-3260668
  • issue/automatic_updates-3261637
  • issue/automatic_updates-3261772
  • issue/automatic_updates-3261847
  • issue/automatic_updates-3262016
  • issue/automatic_updates-3262244
  • issue/automatic_updates-3262303
  • issue/automatic_updates-3261642
  • issue/automatic_updates-3262359
  • issue/automatic_updates-3262542
  • issue/automatic_updates-3261098
  • issue/automatic_updates-3260666
  • issue/automatic_updates-3262587
  • issue/automatic_updates-3262965
  • issue/automatic_updates-3263155
  • issue/automatic_updates-3263223
  • issue/automatic_updates-3254755
  • issue/automatic_updates-3261758
  • issue/automatic_updates-3258059
  • issue/automatic_updates-3259196
  • issue/automatic_updates-3263865
  • issue/automatic_updates-3262284
  • issue/automatic_updates-3264554
  • issue/automatic_updates-3248928
  • issue/automatic_updates-3248929
  • issue/automatic_updates-3265072
  • issue/automatic_updates-3265057
  • issue/automatic_updates-3265873
  • issue/automatic_updates-3266092
  • issue/automatic_updates-3266633
  • issue/automatic_updates-3266640
  • issue/automatic_updates-3266687
  • issue/automatic_updates-3266981
  • issue/automatic_updates-3267387
  • issue/automatic_updates-3267389
  • issue/automatic_updates-3267411
  • issue/automatic_updates-3267603
  • issue/automatic_updates-3265874
  • issue/automatic_updates-3267577
  • issue/automatic_updates-3267386
  • issue/automatic_updates-3268363
  • issue/automatic_updates-3268868
  • issue/automatic_updates-3268612
  • issue/automatic_updates-3269097
  • issue/automatic_updates-3267632
  • issue/automatic_updates-3270736
  • issue/automatic_updates-3271144
  • issue/automatic_updates-3271226
  • issue/automatic_updates-3271078
  • issue/automatic_updates-3271371
  • issue/automatic_updates-3267646
  • issue/automatic_updates-3272060
  • issue/automatic_updates-3265031
  • issue/automatic_updates-3253591
  • issue/automatic_updates-3272520
  • issue/automatic_updates-3272061
  • issue/automatic_updates-3272785
  • issue/automatic_updates-3273011
  • issue/automatic_updates-3273008
  • issue/automatic_updates-3273364
  • issue/automatic_updates-3273407
  • issue/automatic_updates-3271235
  • issue/automatic_updates-3273006
  • issue/automatic_updates-3271240
  • issue/automatic_updates-3271468
  • issue/automatic_updates-3272326
  • issue/automatic_updates-3273693
  • issue/automatic_updates-3264849
  • issue/automatic_updates-3273807
  • issue/automatic_updates-3273017
  • issue/automatic_updates-3274269
  • issue/automatic_updates-3274273
  • issue/automatic_updates-3274292
  • issue/automatic_updates-3273812
  • issue/automatic_updates-3274323
  • issue/automatic_updates-3274633
  • issue/automatic_updates-3274858
  • issue/automatic_updates-3274830
  • issue/automatic_updates-3274892
  • issue/automatic_updates-3275075
  • issue/automatic_updates-3275256
  • issue/automatic_updates-3275282
  • issue/automatic_updates-3275320
  • issue/automatic_updates-3275323
  • issue/automatic_updates-3275324
  • issue/automatic_updates-3275317
  • issue/automatic_updates-3275313
  • issue/automatic_updates-3275357
  • issue/automatic_updates-3275474
  • issue/automatic_updates-3275311
  • issue/automatic_updates-3275546
  • issue/automatic_updates-3275508
  • issue/automatic_updates-3275810
  • issue/automatic_updates-3275860
  • issue/automatic_updates-3275865
  • issue/automatic_updates-3275886
  • issue/automatic_updates-3275887
  • issue/automatic_updates-3276031
  • issue/automatic_updates-3276041
  • issue/automatic_updates-3276072
  • issue/automatic_updates-3276159
  • issue/automatic_updates-3276255
  • issue/automatic_updates-3275825
  • issue/automatic_updates-3276661
  • issue/automatic_updates-3275369
  • issue/automatic_updates-3277014
  • issue/automatic_updates-3277035
  • issue/automatic_updates-3272813
  • issue/automatic_updates-3277211
  • issue/automatic_updates-3277229
  • issue/automatic_updates-3275316
  • issue/automatic_updates-3274047
  • issue/automatic_updates-3277815
  • issue/automatic_updates-3276662
  • issue/automatic_updates-3277235
  • issue/automatic_updates-3278411
  • issue/automatic_updates-3278435
  • issue/automatic_updates-3279229
  • issue/automatic_updates-3277007
  • issue/automatic_updates-3284346
  • issue/automatic_updates-3239759
  • issue/automatic_updates-3284495
  • issue/automatic_updates-3284530
  • issue/automatic_updates-3282677
  • issue/automatic_updates-3281379
  • issue/automatic_updates-3285408
  • issue/automatic_updates-3285631
  • issue/automatic_updates-3285669
  • issue/automatic_updates-3273014
  • issue/automatic_updates-3273369
  • issue/automatic_updates-3285491
  • issue/automatic_updates-3285898
  • issue/automatic_updates-3287251
  • issue/automatic_updates-3291147
  • issue/automatic_updates-3286650
  • issue/automatic_updates-3291770
  • issue/automatic_updates-3280403
  • issue/automatic_updates-3291959
  • issue/automatic_updates-3287398
  • issue/automatic_updates-3285145
  • issue/automatic_updates-3292027
  • issue/automatic_updates-3278445
  • issue/automatic_updates-3292933
  • issue/automatic_updates-3292958
  • issue/automatic_updates-3293157
  • issue/automatic_updates-3292956
  • issue/automatic_updates-3293146
  • issue/automatic_updates-3293381
  • issue/automatic_updates-3293449
  • issue/automatic_updates-3293427
  • issue/automatic_updates-3293422
  • issue/automatic_updates-3293685
  • issue/automatic_updates-3291730
  • issue/automatic_updates-3293866
  • issue/automatic_updates-3294338
  • issue/automatic_updates-3293656
  • issue/automatic_updates-3294600
  • issue/automatic_updates-3294335
  • issue/automatic_updates-3295013
  • issue/automatic_updates-3284936
  • issue/automatic_updates-3295596
  • issue/automatic_updates-3295758
  • issue/automatic_updates-3295791
  • issue/automatic_updates-3295830
  • issue/automatic_updates-3295874
  • issue/automatic_updates-3295897
  • issue/automatic_updates-3296074
  • issue/automatic_updates-3295965
  • issue/automatic_updates-3296181
  • issue/automatic_updates-3296065
  • issue/automatic_updates-3296178
  • issue/automatic_updates-3296261
  • issue/automatic_updates-3293148
  • issue/automatic_updates-3303953
  • issue/automatic_updates-3304367
  • issue/automatic_updates-3304640
  • issue/automatic_updates-3304836
  • issue/automatic_updates-3304142
  • issue/automatic_updates-3298349
  • issue/automatic_updates-3298444
  • issue/automatic_updates-3298510
  • issue/automatic_updates-3298431
  • issue/automatic_updates-3298863
  • issue/automatic_updates-3298877
  • issue/automatic_updates-3298904
  • issue/automatic_updates-3298951
  • issue/automatic_updates-3299101
  • issue/automatic_updates-3299417
  • issue/automatic_updates-3293417
  • issue/automatic_updates-3299612
  • issue/automatic_updates-3299093
  • issue/automatic_updates-3299087
  • issue/automatic_updates-3300006
  • issue/automatic_updates-3300036
  • issue/automatic_updates-3293150
  • issue/automatic_updates-3303807
  • issue/automatic_updates-3303929
  • issue/automatic_updates-3304417
  • issue/automatic_updates-3303727
  • issue/automatic_updates-3305527
  • issue/automatic_updates-3301844
  • issue/automatic_updates-3302527
  • issue/automatic_updates-3302673
  • issue/automatic_updates-3302897
  • issue/automatic_updates-3303143
  • issue/automatic_updates-3303168
  • issue/automatic_updates-3303174
  • issue/automatic_updates-3303185
  • issue/automatic_updates-3303200
  • issue/automatic_updates-3303113
  • issue/automatic_updates-3304036
  • issue/automatic_updates-3304165
  • issue/automatic_updates-3304583
  • issue/automatic_updates-3303902
  • issue/automatic_updates-3304651
  • issue/automatic_updates-3305312
  • issue/automatic_updates-3305612
  • issue/automatic_updates-3305568
  • issue/automatic_updates-3305773
  • issue/automatic_updates-3305874
  • issue/automatic_updates-3310901
  • issue/automatic_updates-3310929
  • issue/automatic_updates-3310936
  • issue/automatic_updates-3310972
  • issue/automatic_updates-3311001
  • issue/automatic_updates-3311020
  • issue/automatic_updates-3305240
  • issue/automatic_updates-3305994
  • issue/automatic_updates-3305564
  • issue/automatic_updates-3305998
  • issue/automatic_updates-3306600
  • issue/automatic_updates-3306631
  • issue/automatic_updates-3307086
  • issue/automatic_updates-3307103
  • issue/automatic_updates-3307168
  • issue/automatic_updates-3306163
  • issue/automatic_updates-3304617
  • issue/automatic_updates-3307163
  • issue/automatic_updates-3307398
  • issue/automatic_updates-3307478
  • issue/automatic_updates-3307369
  • issue/automatic_updates-3308404
  • issue/automatic_updates-3307611
  • issue/automatic_updates-3308372
  • issue/automatic_updates-3308686
  • issue/automatic_updates-3308886
  • issue/automatic_updates-3309220
  • issue/automatic_updates-3309270
  • issue/automatic_updates-3308711
  • issue/automatic_updates-3309486
  • issue/automatic_updates-3305167
  • issue/automatic_updates-3309676
  • issue/automatic_updates-3309025
  • issue/automatic_updates-3309891
  • issue/automatic_updates-3308365
  • issue/automatic_updates-3310000
  • issue/automatic_updates-3309205
  • issue/automatic_updates-3248975
  • issue/automatic_updates-3310702
  • issue/automatic_updates-3272313
  • issue/automatic_updates-3310990
  • issue/automatic_updates-3310997
  • issue/automatic_updates-3311200
  • issue/automatic_updates-3310696
  • issue/automatic_updates-3311265
  • issue/automatic_updates-3303167
  • issue/automatic_updates-3310946
  • issue/automatic_updates-3308828
  • issue/automatic_updates-3310666
  • issue/automatic_updates-3109082
  • issue/automatic_updates-3311534
  • issue/automatic_updates-3311436
  • issue/automatic_updates-3308843
  • issue/automatic_updates-3303900
  • issue/automatic_updates-3312085
  • issue/automatic_updates-3312420
  • issue/automatic_updates-3312373
  • issue/automatic_updates-3312421
  • issue/automatic_updates-3312619
  • issue/automatic_updates-3312779
  • issue/automatic_updates-3275991
  • issue/automatic_updates-3312938
  • issue/automatic_updates-3312937
  • issue/automatic_updates-3312960
  • issue/automatic_updates-3312669
  • issue/automatic_updates-3312981
  • issue/automatic_updates-3313319
  • issue/automatic_updates-3313346
  • issue/automatic_updates-3310914
  • issue/automatic_updates-3317220
  • issue/automatic_updates-3317232
  • issue/automatic_updates-3317278
  • issue/automatic_updates-3317409
  • issue/automatic_updates-3317267
  • issue/automatic_updates-3317599
  • issue/automatic_updates-3317988
  • issue/automatic_updates-3318313
  • issue/automatic_updates-3313630
  • issue/automatic_updates-3313717
  • issue/automatic_updates-3313947
  • issue/automatic_updates-3313507
  • issue/automatic_updates-3276645
  • issue/automatic_updates-3313349
  • issue/automatic_updates-3314137
  • issue/automatic_updates-3314143
  • issue/automatic_updates-3304365
  • issue/automatic_updates-3317796
  • issue/automatic_updates-3317996
  • issue/automatic_updates-3316484
  • issue/automatic_updates-3313414
  • issue/automatic_updates-3314764
  • issue/automatic_updates-3314771
  • issue/automatic_updates-3314787
  • issue/automatic_updates-3314805
  • issue/automatic_updates-3314734
  • issue/automatic_updates-3298889
  • issue/automatic_updates-3314803
  • issue/automatic_updates-3315139
  • issue/automatic_updates-3314946
  • issue/automatic_updates-3315449
  • issue/automatic_updates-3315798
  • issue/automatic_updates-3315834
  • issue/automatic_updates-3309602
  • issue/automatic_updates-3316115
  • issue/automatic_updates-3316131
  • issue/automatic_updates-3316293
  • issue/automatic_updates-3316318
  • issue/automatic_updates-3310729
  • issue/automatic_updates-3315700
  • issue/automatic_updates-3316668
  • issue/automatic_updates-3316721
  • issue/automatic_updates-3306283
  • issue/automatic_updates-3316611
  • issue/automatic_updates-3316895
  • issue/automatic_updates-3317385
  • issue/automatic_updates-3318625
  • issue/automatic_updates-3318770
  • issue/automatic_updates-3318846
  • issue/automatic_updates-3318927
  • issue/automatic_updates-3318933
  • issue/automatic_updates-3319044
  • issue/automatic_updates-3319045
  • issue/automatic_updates-3325716
  • issue/automatic_updates-3324421
  • issue/automatic_updates-3320486
  • issue/automatic_updates-3320558
  • issue/automatic_updates-3321206
  • issue/automatic_updates-3326934
  • issue/automatic_updates-3320755
  • issue/automatic_updates-3328765
  • issue/automatic_updates-3325654
  • issue/automatic_updates-3325869
  • issue/automatic_updates-3277034
  • issue/automatic_updates-3328516
  • issue/automatic_updates-3322546
  • issue/automatic_updates-3320487
  • issue/automatic_updates-3320792
  • issue/automatic_updates-3320815
  • issue/automatic_updates-3320638
  • issue/automatic_updates-3321256
  • issue/automatic_updates-3321684
  • issue/automatic_updates-3325522
  • issue/automatic_updates-3326334
  • issue/automatic_updates-3328234
  • issue/automatic_updates-3328740
  • issue/automatic_updates-3316932
  • issue/automatic_updates-3321386
  • issue/automatic_updates-3321933
  • issue/automatic_updates-3321282
  • issue/automatic_updates-3326801
  • issue/automatic_updates-3327753
  • issue/automatic_updates-3328742
  • issue/automatic_updates-3322313
  • issue/automatic_updates-3322203
  • issue/automatic_updates-3322150
  • issue/automatic_updates-3322404
  • issue/automatic_updates-3321236
  • issue/automatic_updates-3321994
  • issue/automatic_updates-3322589
  • issue/automatic_updates-3321904
  • issue/automatic_updates-3316855
  • issue/automatic_updates-3322931
  • issue/automatic_updates-3322913
  • issue/automatic_updates-3323037
  • issue/automatic_updates-3322918
  • issue/automatic_updates-3323211
  • issue/automatic_updates-3323565
  • issue/automatic_updates-3320824
  • issue/automatic_updates-3320836
  • issue/automatic_updates-3329002
  • issue/automatic_updates-3321971
  • issue/automatic_updates-3299094
  • issue/automatic_updates-3248544
  • issue/automatic_updates-3330139
  • issue/automatic_updates-3330365
  • issue/automatic_updates-3330712
  • issue/automatic_updates-3318065
  • issue/automatic_updates-3331310
  • issue/automatic_updates-3322917
  • issue/automatic_updates-3330140
  • issue/automatic_updates-3323003
  • issue/automatic_updates-3331355
  • issue/automatic_updates-3334054
  • issue/automatic_updates-3323706
  • issue/automatic_updates-3331168
  • issue/automatic_updates-3343430
  • issue/automatic_updates-3344562
  • issue/automatic_updates-3345039
  • issue/automatic_updates-3344039
  • issue/automatic_updates-3345313
  • issue/automatic_updates-3331471
  • issue/automatic_updates-3334994
  • issue/automatic_updates-3327229
  • issue/automatic_updates-3343889
  • issue/automatic_updates-3344124
  • issue/automatic_updates-3344689
  • issue/automatic_updates-3316368
  • issue/automatic_updates-3345767
  • issue/automatic_updates-3317815
  • issue/automatic_updates-3328600
  • issue/automatic_updates-3332256
  • issue/automatic_updates-3335766
  • issue/automatic_updates-3335802
  • issue/automatic_updates-3335908
  • issue/automatic_updates-3336243
  • issue/automatic_updates-3336247
  • issue/automatic_updates-3336255
  • issue/automatic_updates-3336259
  • issue/automatic_updates-3337062
  • issue/automatic_updates-3337068
  • issue/automatic_updates-3311229
  • issue/automatic_updates-3337697
  • issue/automatic_updates-3343768
  • issue/automatic_updates-3344127
  • issue/automatic_updates-3344595
  • issue/automatic_updates-3345763
  • issue/automatic_updates-3345765
  • issue/automatic_updates-3345771
  • issue/automatic_updates-3337760
  • issue/automatic_updates-3337049
  • issue/automatic_updates-3342430
  • issue/automatic_updates-3319507
  • issue/automatic_updates-3344583
  • issue/automatic_updates-3345764
  • issue/automatic_updates-3345768
  • issue/automatic_updates-3338667
  • issue/automatic_updates-3339016
  • issue/automatic_updates-3343827
  • issue/automatic_updates-3344556
  • issue/automatic_updates-3338666
  • issue/automatic_updates-3345649
  • issue/automatic_updates-3339657
  • issue/automatic_updates-3339719
  • issue/automatic_updates-3338789
  • issue/automatic_updates-3340022
  • issue/automatic_updates-3340284
  • issue/automatic_updates-3340638
  • issue/automatic_updates-3316617
  • issue/automatic_updates-3341224
  • issue/automatic_updates-3337953
  • issue/automatic_updates-3339714
  • issue/automatic_updates-3341708
  • issue/automatic_updates-3341841
  • issue/automatic_updates-3326486
  • issue/automatic_updates-3321474
  • issue/automatic_updates-3341974
  • issue/automatic_updates-3342120
  • issue/automatic_updates-3342227
  • issue/automatic_updates-3323461
  • issue/automatic_updates-3342137
  • issue/automatic_updates-3342460
  • issue/automatic_updates-3342364
  • issue/automatic_updates-3345028
  • issue/automatic_updates-3345549
  • issue/automatic_updates-3345881
  • issue/automatic_updates-3345762
  • issue/automatic_updates-3342726
  • issue/automatic_updates-3337667
  • issue/automatic_updates-3343463
  • issue/automatic_updates-3345766
  • issue/automatic_updates-3345754
  • issue/automatic_updates-3345633
  • issue/automatic_updates-3345772
  • issue/automatic_updates-3345769
  • issue/automatic_updates-3345761
  • issue/automatic_updates-3345755
  • issue/automatic_updates-3345760
  • issue/automatic_updates-3345757
  • issue/automatic_updates-3346520
  • issue/automatic_updates-3346545
  • issue/automatic_updates-3337054
  • issue/automatic_updates-3346628
  • issue/automatic_updates-3346717
  • issue/automatic_updates-3346594
  • issue/automatic_updates-3346659
  • issue/automatic_updates-3347031
  • issue/automatic_updates-3346547
  • issue/automatic_updates-3347164
  • issue/automatic_updates-3318306
  • issue/automatic_updates-3345646
  • issue/automatic_updates-3347165
  • issue/automatic_updates-3347959
  • issue/automatic_updates-3347267
  • issue/automatic_updates-3338346
  • issue/automatic_updates-3348122
  • issue/automatic_updates-3348129
  • issue/automatic_updates-3348162
  • issue/automatic_updates-3348276
  • issue/automatic_updates-3348441
  • issue/automatic_updates-3351604
  • issue/automatic_updates-3316843
  • issue/automatic_updates-3351908
  • issue/automatic_updates-3352731
  • issue/automatic_updates-3352898
  • issue/automatic_updates-3348866
  • issue/automatic_updates-3342817
  • issue/automatic_updates-3348159
  • issue/automatic_updates-3349142
  • issue/automatic_updates-3349966
  • issue/automatic_updates-3350909
  • issue/automatic_updates-3351594
  • issue/automatic_updates-3351883
  • issue/automatic_updates-3351925
  • issue/automatic_updates-3352198
  • issue/automatic_updates-3334552
  • issue/automatic_updates-3342790
  • issue/automatic_updates-3345222
  • issue/automatic_updates-3351212
  • issue/automatic_updates-3351093
  • issue/automatic_updates-3351247
  • issue/automatic_updates-3351962
  • issue/automatic_updates-3345641
  • issue/automatic_updates-3338940
  • issue/automatic_updates-3343721
  • issue/automatic_updates-3351069
  • issue/automatic_updates-3353219
  • issue/automatic_updates-3159920
  • issue/automatic_updates-3352355
  • issue/automatic_updates-3341469
  • issue/automatic_updates-3354099
  • issue/automatic_updates-3339659
  • issue/automatic_updates-3354312
  • issue/automatic_updates-3351895
  • issue/automatic_updates-3354249
  • issue/automatic_updates-3353270
  • issue/automatic_updates-3354003
  • issue/automatic_updates-3355074
  • issue/automatic_updates-3355094
  • issue/automatic_updates-3355105
  • issue/automatic_updates-3355162
  • issue/automatic_updates-3355446
  • issue/automatic_updates-3355045
  • issue/automatic_updates-3355558
  • issue/automatic_updates-3355553
  • issue/automatic_updates-3354594
  • issue/automatic_updates-3355609
  • issue/automatic_updates-3354325
  • issue/automatic_updates-3356395
  • issue/automatic_updates-3356638
  • issue/automatic_updates-3356640
  • issue/automatic_updates-3354701
  • issue/automatic_updates-3355463
  • issue/automatic_updates-3356804
  • issue/automatic_updates-3357721
  • issue/automatic_updates-3357578
  • issue/automatic_updates-3357657
  • issue/automatic_updates-3304108
  • issue/automatic_updates-3357941
  • issue/automatic_updates-3358012
  • issue/automatic_updates-3345535
  • issue/automatic_updates-3354827
  • issue/automatic_updates-3358570
  • issue/automatic_updates-3358878
  • issue/automatic_updates-3355628
  • issue/automatic_updates-3358504
  • issue/automatic_updates-3357969
  • issue/automatic_updates-3359609
  • issue/automatic_updates-3359727
  • issue/automatic_updates-3359825
  • issue/automatic_updates-3359820
  • issue/automatic_updates-3360548
  • issue/automatic_updates-3357480
  • issue/automatic_updates-3360656
  • issue/automatic_updates-3360763
  • issue/automatic_updates-3360655
  • issue/automatic_updates-3355618
  • issue/automatic_updates-3349351
  • issue/automatic_updates-3362110
  • issue/automatic_updates-3362143
  • issue/automatic_updates-3362589
  • issue/automatic_updates-3349004
  • issue/automatic_updates-3362507
  • issue/automatic_updates-3362746
  • issue/automatic_updates-3362978
  • issue/automatic_updates-3363259
  • issue/automatic_updates-3363725
  • issue/automatic_updates-3363926
  • issue/automatic_updates-3363937
  • issue/automatic_updates-3364514
  • issue/automatic_updates-3284443
  • issue/automatic_updates-3363938
  • issue/automatic_updates-3364731
  • issue/automatic_updates-3364748
  • issue/automatic_updates-3364735
  • issue/automatic_updates-3364725
  • issue/automatic_updates-3359670
  • issue/automatic_updates-3365133
  • issue/automatic_updates-3365151
  • issue/automatic_updates-3365177
  • issue/automatic_updates-3364958
  • issue/automatic_updates-3365390
  • issue/automatic_updates-3365414
  • issue/automatic_updates-3346644
  • issue/automatic_updates-3366267
  • issue/automatic_updates-3366289
  • issue/automatic_updates-3366499
  • issue/automatic_updates-3365437
  • issue/automatic_updates-3354914
  • issue/automatic_updates-3253828
  • issue/automatic_updates-3345484
  • issue/automatic_updates-3352846
  • issue/automatic_updates-3368741
  • issue/automatic_updates-3406008
  • issue/automatic_updates-3406122
  • issue/automatic_updates-3370197
  • issue/automatic_updates-3366271
  • issue/automatic_updates-3364135
  • issue/automatic_updates-3370603
  • issue/automatic_updates-3400146
  • issue/automatic_updates-3406010
  • issue/automatic_updates-3404429
  • issue/automatic_updates-3371212
  • issue/automatic_updates-3371076
  • issue/automatic_updates-3372673
  • issue/automatic_updates-3368808
  • issue/automatic_updates-3374175
  • issue/automatic_updates-3374739
  • issue/automatic_updates-3374753
  • issue/automatic_updates-3375679
  • issue/automatic_updates-3377237
  • issue/automatic_updates-3377245
  • issue/automatic_updates-3378774
  • issue/automatic_updates-3378793
  • issue/automatic_updates-3360485
  • issue/automatic_updates-3380698
  • issue/automatic_updates-3375940
  • issue/automatic_updates-3381294
  • issue/automatic_updates-3381484
  • issue/automatic_updates-3382942
  • issue/automatic_updates-3383462
  • issue/automatic_updates-3383451
  • issue/automatic_updates-3384359
  • issue/automatic_updates-3384637
  • issue/automatic_updates-3375640
  • issue/automatic_updates-3386135
  • issue/automatic_updates-3386533
  • issue/automatic_updates-3387610
  • issue/automatic_updates-3387637
  • issue/automatic_updates-3387656
  • issue/automatic_updates-3389157
  • issue/automatic_updates-3388965
  • issue/automatic_updates-3387379
  • issue/automatic_updates-3390493
  • issue/automatic_updates-3308235
  • issue/automatic_updates-3391715
  • issue/automatic_updates-3392246
  • issue/automatic_updates-3393633
  • issue/automatic_updates-3379344
  • issue/automatic_updates-3394413
  • issue/automatic_updates-3394705
  • issue/automatic_updates-3394936
  • issue/automatic_updates-3363497
  • issue/automatic_updates-3395782
  • issue/automatic_updates-3341406
  • issue/automatic_updates-3311472
  • issue/automatic_updates-3397228
  • issue/automatic_updates-3352654
  • issue/automatic_updates-3398782
  • issue/automatic_updates-3399147
  • issue/automatic_updates-3399155
  • issue/automatic_updates-3406812
  • issue/automatic_updates-3408483
  • issue/automatic_updates-3408488
  • issue/automatic_updates-3408560
  • issue/automatic_updates-3437633
  • issue/automatic_updates-3408835
  • issue/automatic_updates-3408937
  • issue/automatic_updates-3409491
  • issue/automatic_updates-3409519
  • issue/automatic_updates-3377458
  • issue/automatic_updates-3437951
  • issue/automatic_updates-3409774
  • issue/automatic_updates-3410047
  • issue/automatic_updates-3411110
  • issue/automatic_updates-3411241
  • issue/automatic_updates-3411276
  • issue/automatic_updates-3411392
  • issue/automatic_updates-3411240
  • issue/automatic_updates-3412630
  • issue/automatic_updates-3413866
  • issue/automatic_updates-3414168
  • issue/automatic_updates-3415291
  • issue/automatic_updates-3415389
  • issue/automatic_updates-3415403
  • issue/automatic_updates-3416768
  • issue/automatic_updates-3417905
  • issue/automatic_updates-3420188
  • issue/automatic_updates-3421641
  • issue/automatic_updates-3424290
  • issue/automatic_updates-3426229
  • issue/automatic_updates-3426666
  • issue/automatic_updates-3426716
  • issue/automatic_updates-3428199
  • issue/automatic_updates-3436741
  • issue/automatic_updates-3441923
  • issue/automatic_updates-3428651
  • issue/automatic_updates-3441799
  • issue/automatic_updates-3443249
  • issue/automatic_updates-3428922
  • issue/automatic_updates-3441817
  • issue/automatic_updates-3429248
  • issue/automatic_updates-3440646
  • issue/automatic_updates-3437877
  • issue/automatic_updates-3445149
  • issue/automatic_updates-3429268
  • issue/automatic_updates-3442153
  • issue/automatic_updates-3438156
  • issue/automatic_updates-3436993
  • issue/automatic_updates-3437704
  • issue/automatic_updates-3432496
  • issue/automatic_updates-3440006
  • issue/automatic_updates-3435893
  • issue/automatic_updates-3441577
  • issue/automatic_updates-3437023
  • issue/automatic_updates-3432391
  • issue/automatic_updates-3432447
  • issue/automatic_updates-3432472
  • issue/automatic_updates-3432489
  • issue/automatic_updates-3432476
  • issue/automatic_updates-3435918
  • issue/automatic_updates-3439067
  • issue/automatic_updates-3437409
  • issue/automatic_updates-3449093
  • issue/automatic_updates-3449480
  • issue/automatic_updates-3449519
  • issue/automatic_updates-3449631
  • issue/automatic_updates-3449636
  • issue/automatic_updates-3449689
  • issue/automatic_updates-3449693
  • issue/automatic_updates-3450884
  • issue/automatic_updates-3452870
  • issue/automatic_updates-3453030
  • issue/automatic_updates-3455161
  • issue/automatic_updates-3459557
  • issue/automatic_updates-3462138
  • issue/automatic_updates-3462168
  • issue/automatic_updates-3462883
  • issue/automatic_updates-3463662
  • issue/automatic_updates-3463813
  • issue/automatic_updates-3446371
  • issue/automatic_updates-3465155
  • issue/automatic_updates-3340355
  • issue/automatic_updates-3467749
  • issue/automatic_updates-3473410
  • issue/automatic_updates-3441926
  • issue/automatic_updates-3474603
  • issue/automatic_updates-3484802
  • issue/automatic_updates-3498586
  • issue/automatic_updates-3499481
  • issue/automatic_updates-3498018
  • issue/automatic_updates-3506632
  • issue/automatic_updates-3511959
  • issue/automatic_updates-3511943
981 results
Show changes
Commits on Source (520)
Showing
with 1070 additions and 513 deletions
{
"dictionaries": ["drupal","companies", "fonts", "html", "php", "softwareTerms", "automatic_updates"],
"dictionaryDefinitions": [
{ "name": "automatic_updates", "path": "./dictionary.txt"}
],
"ignorePaths": [
"README.md"
]
}
/dictionary.txt export-ignore
/scripts export-ignore
/.idea
/auto-updates-dev
################
# DrupalCI GitLabCI template
#
# Gitlab-ci.yml to replicate DrupalCI testing for Contrib
#
# With thanks to:
# * The GitLab Acceleration Initiative participants
# * DrupalSpoons
################
################
# Guidelines
#
# This template is designed to give any Contrib maintainer everything they need to test, without requiring modification. It is also designed to keep up to date with Core Development automatically through the use of include files that can be centrally maintained.
#
# However, you can modify this template if you have additional needs for your project.
################
################
# Includes
#
# Additional configuration can be provided through includes.
# One advantage of include files is that if they are updated upstream, the changes affect all pipelines using that include.
#
# Includes can be overridden by re-declaring anything provided in an include, here in gitlab-ci.yml
# https://docs.gitlab.com/ee/ci/yaml/includes.html#override-included-configuration-values
################
include:
################
# DrupalCI includes:
# As long as you include this, any future includes added by the Drupal Association will be accessible to your pipelines automatically.
# View these include files at https://git.drupalcode.org/project/gitlab_templates/
################
- project: $_GITLAB_TEMPLATES_REPO
# "ref" value can be:
# - Recommended (default) - `ref: $_GITLAB_TEMPLATES_REF` - The Drupal Association will update this value to the recommended tag for contrib.
# - Latest - `ref: main` - Get the latest additions and bug fixes as they are merged into the templates.
# - Minor or Major latests - `ref: 1.x-latest` or `ref: 1.0.x-latest` - Get the latest additions within a minor (mostly bugfixes) or major (bugs and new features).
# - Fixed tag - `ref: 1.0.1` - Set the value to a known tag. This will not get any updates.
# If you change the default value of ref, you should set the _CURL_TEMPLATES_REF variable in the variables section to be the same as set here.
ref: $_GITLAB_TEMPLATES_REF
file:
- '/includes/include.drupalci.main.yml'
# EXPERIMENTAL: For Drupal 7, remove the above line and uncomment the below.
# - '/includes/include.drupalci.main-d7.yml'
- '/includes/include.drupalci.variables.yml'
- '/includes/include.drupalci.workflows.yml'
################
# Pipeline configuration variables
#
# These are the variables provided to the Run Pipeline form that a user may want to override.
#
# Docs at https://git.drupalcode.org/project/gitlab_templates/-/blob/1.0.x/includes/include.drupalci.variables.yml
################
variables:
_PHPUNIT_CONCURRENT: '1'
_PHPUNIT_TESTGROUPS: ''
# Always test against the previous minor version of core.
OPT_IN_TEST_PREVIOUS_MINOR: '1'
# @todo Remove this line when https://drupal.org/i/3414093 is fixed.
CI_DEBUG_SERVICES: "true"
_TARGET_DB_TYPE: "mariadb"
_TARGET_DB_VERSION: "10.6"
# Always show environment variables, to help in debugging CI problems.
_SHOW_ENVIRONMENT_VARIABLES: '1'
###################################################################################
#
# *
# /(
# ((((,
# /(((((((
# ((((((((((*
# ,(((((((((((((((
# ,(((((((((((((((((((
# ((((((((((((((((((((((((*
# *(((((((((((((((((((((((((((((
# ((((((((((((((((((((((((((((((((((*
# *(((((((((((((((((( .((((((((((((((((((
# ((((((((((((((((((. /(((((((((((((((((*
# /((((((((((((((((( .(((((((((((((((((,
# ,(((((((((((((((((( ((((((((((((((((((
# .(((((((((((((((((((( .(((((((((((((((((
# ((((((((((((((((((((((( ((((((((((((((((/
# (((((((((((((((((((((((((((/ ,(((((((((((((((*
# .((((((((((((((/ /(((((((((((((. ,(((((((((((((((
# *(((((((((((((( ,(((((((((((((/ *((((((((((((((.
# ((((((((((((((, /(((((((((((((. ((((((((((((((,
# (((((((((((((/ ,(((((((((((((* ,(((((((((((((,
# *((((((((((((( .((((((((((((((( ,(((((((((((((
# ((((((((((((/ /((((((((((((((((((. ,((((((((((((/
# ((((((((((((( *(((((((((((((((((((((((* *((((((((((((
# ((((((((((((( ,(((((((((((((..((((((((((((( *((((((((((((
# ((((((((((((, /((((((((((((* /((((((((((((/ ((((((((((((
# ((((((((((((( /((((((((((((/ (((((((((((((* ((((((((((((
# (((((((((((((/ /(((((((((((( ,((((((((((((, *((((((((((((
# (((((((((((((( *(((((((((((/ *((((((((((((. ((((((((((((/
# *((((((((((((((((((((((((((, /(((((((((((((((((((((((((
# ((((((((((((((((((((((((( ((((((((((((((((((((((((,
# .(((((((((((((((((((((((/ ,(((((((((((((((((((((((
# ((((((((((((((((((((((/ ,(((((((((((((((((((((/
# *((((((((((((((((((((( (((((((((((((((((((((,
# ,(((((((((((((((((((((, ((((((((((((((((((((/
# ,(((((((((((((((((((((* /((((((((((((((((((((
# ((((((((((((((((((((((, ,/((((((((((((((((((((,
# ,(((((((((((((((((((((((((((((((((((((((((((((((((((
# .(((((((((((((((((((((((((((((((((((((((((((((
# .((((((((((((((((((((((((((((((((((((,.
# .,(((((((((((((((((((((((((.
#
###################################################################################
.extra-variables: &extra-variables
- MODULE_DIR=$_WEB_ROOT/modules/custom/$CI_PROJECT_NAME
# Strip the `-dev` suffix out of $_TARGET_CORE to reveal the name of the Drupal core branch.
- CORE_BRANCH=`echo $_TARGET_CORE | sed -e "s/-dev$//"`
composer:
extends: .composer-base
before_script:
# In this case, we want to archive everything.
- rm .gitattributes
- composer archive --file=module
after_script:
- *extra-variables
- rm -r -f $MODULE_DIR
- mkdir -p $MODULE_DIR
- tar -x -f module.tar -C $MODULE_DIR
- rm module.tar
- git clone https://git.drupalcode.org/project/drupal.git --depth 1 --branch $CORE_BRANCH /tmp/drupal-core
- cp -R /tmp/drupal-core/composer .
# Copy to web as well as \Drupal\Composer\Composer will expect it be there.
- cp -R /tmp/drupal-core/composer web
composer (previous minor):
before_script:
- !reference [composer, before_script]
after_script:
- !reference [composer, after_script]
composer (previous minor):
before_script:
- !reference [composer, before_script]
after_script:
- !reference [composer, after_script]
phpcs:
before_script:
# Use core's PHPCS configuration.
- cp $_WEB_ROOT/core/phpcs.xml.dist .
phpstan:
before_script:
- *extra-variables
# Ensure our PHPStan configuration has the correct include path to core's PHPStan configuration.
- sed -i "s#%rootDir%/../../../#%rootDir%/../../../$_WEB_ROOT/#" $MODULE_DIR/phpstan.neon
phpunit:
parallel:
matrix:
- MODULE:
- automatic_updates_extensions
- automatic_updates
- package_manager
TEST_TYPE:
- Unit
- Kernel
- Functional
- FunctionalJavascript
- Build
rules:
# Automatic Updates Extensions has no unit or functional JavaScript tests.
- if: $MODULE == "automatic_updates_extensions" && ($TEST_TYPE == "Unit" || $TEST_TYPE == "FunctionalJavascript")
when: never
# Package Manager has no functional JavaScript tests.
- if: $MODULE == "package_manager" && $TEST_TYPE == "FunctionalJavascript"
when: never
- when: on_success
variables:
_PHPUNIT_EXTRA: '--types PHPUnit-$TEST_TYPE --module $MODULE'
phpunit (previous minor):
rules:
- !reference [phpunit, rules]
### Prerequisites
* PHP 7.4 or later.
# Local development environment setup
## Quick setup
A simple setup is enough for most users to start contributing to Automatic Updates. For advanced needs, see [Customizing your setup](#customizing-your-setup) and [Alternative setup options](#alternative-setup-options).
Assuming you meet the [system requirements](#system-requirements), simply run the following command <sup>[[1]](#footnote-1), [[2]](#footnote-2)</sup> from the directory you would like to install your development environment under <sup>[[3]](#footnote-3)</sup>. It will prompt for confirmation before beginning.
```shell
/bin/bash -c "$(curl -fsSL https://git.drupalcode.org/project/automatic_updates/-/raw/3.0.x/scripts/setup_local_dev.sh)"
```
That's it. The success message will display next steps.
## Details and options
---
* [System requirements](#system-requirements)
* [Caveats](#caveats)
* [Customizing your setup](#customizing-your-setup)
* [Alternative setup options](#alternative-setup-options)
* [Maintaining your environment](#maintaining-your-environment)
---
### System requirements
* A *nix-based operating system, such as Linux or macOS.
* Drupal 10 or later.
* Composer 2 or later. (Automatic Updates is not compatible with Composer 1.)
* Git must be installed.
### Caveats
* Symbolic links are not currently supported by Package Manager. If the Drupal core checkout contains any symbolic links, tests will not work. By default, there shouldn't be any, but some may exist in certain situations (for example, if Drush or Drupal core's JavaScript dependencies have been installed). To scan for symbolic links, run `find . -type l` from the Drupal core repository root.
### Customizing your setup
Several details of your setup can be customized via environment variables. Set these before running [the installation command above](#local-development-environment-setup).
### Step 1: Set up Drupal core
For development and running the module's tests, Automatic Updates assumes you are working from a Git clone of Drupal core. To set one up:
```shell
DRUPAL_CORE_BRANCH="10.0.x" # The branch of Drupal core that will be installed.
DRUPAL_CORE_SHALLOW_CLONE="TRUE" # Whether or not to do a "shallow clone" of Drupal core. (Defaults to TRUE.) See note below.
AUTOMATIC_UPDATES_BRANCH="3.0.x" # The branch of the Automatic Updates module that will be installed.
SITE_DIRECTORY="auto_updates_dev" # The path to the directory where the dev environment will be installed.
SITE_HOST=".test" # The path for Drupal's TRUSTED_HOST_PATTERN.
```
git clone https://git.drupalcode.org/project/drupal.git --branch 9.5.x auto-updates-dev
Note: A shallow Git clone is much smaller and therefore faster, but it removes the ability to do debugging operations such as `git bisect` or `git blame`. To recover these abilities, [you can convert your repository to a full clone after the fact](https://stackoverflow.com/questions/6802145/how-to-convert-a-git-shallow-clone-to-a-full-clone):
// cSpell:disable
```shell
cd auto-updates-dev
composer config platform.php 7.4.0
composer install
git fetch --unshallow
```
Replace `9.5.x` with the desired development branch of Drupal core. Be sure to point your web server to the `auto-updates-dev` directory, so you can access this code base in a browser.
// cSpell:enable
### Step 2: Clone Automatic Updates
Clone Automatic Updates' main development branch (8.x-2.x):
```
git clone --branch '8.x-2.x' https://git.drupalcode.org/project/automatic_updates.git ./modules/automatic_updates
```
### Alternative setup options
You can download the setup script first to review its contents or modify it before running it:
### Step 3: Install dependencies
From the Drupal repository root:
```shell
curl --output setup_local_dev.sh https://git.drupalcode.org/project/automatic_updates/-/raw/3.0.x/scripts/setup_local_dev.sh
./scripts/setup_local_dev.sh
```
composer require php-tuf/composer-stager "symfony/config:^4.4 || ^6.1"
git reset --hard
You can clone the whole repository:
```shell
git clone https://git.drupalcode.org/project/automatic_updates.git
cd automatic_updates
./scripts/setup_local_dev.sh
```
Note: If you switch to a different branch of Drupal core and delete the `vendor` directory, you will need to do this step again after running `composer install`.
To set up your environment manually, use the setup script as a reference.
### Maintaining your environment
* If you want to switch to a different branch of Drupal core during development or if you delete the `vendor` directory, you may will need to do this step again after running `composer install`.
* _DO NOT_ delete the `automatic_updates` module or the `modules` directory it is in or you will lose any code changes forever. As appropriate, commit them and push them to a remote first--unless you don't care about keeping them. (Don't forget branches other than the one you have checked out.)
---
<a name="footnote-1"><sup>1</sup></a> When running a script downloaded from the Web, it is always wise to read its contents first. Ours ([`setup_local_dev.sh`](https://git.drupalcode.org/project/automatic_updates/-/raw/3.0.x/scripts/setup_local_dev.sh)) is documented with code comments to help with that. For a more cautious approach, see [Alternative setup options](#alternative-setup-options) above.
<a name="footnote-2"><sup>2</sup></a> Curl options explained:
[`-f, --fail`](https://curl.se/docs/manpage.html#-f),
[`-s, --silent`](https://curl.se/docs/manpage.html#-s),
[`-S, --show-error`](https://curl.se/docs/manpage.html#-S),
[`-L, --location`](https://curl.se/docs/manpage.html#-L).
<a name="footnote-3"><sup>3</sup></a> For example, run it in `~/Projects` to create your environment at `~/Projects/auto-updates-dev` or `/var/www` to create it at `/var/www/auto-updates-dev`. See [Customizing your setup](#customizing-your-setup) to override this behavior.
Automatic Updates
---------------
### Requirements
- The Drupal project's codebase must be writable in order to use Automatic Updates. This includes Drupal, modules, themes and the Composer dependencies in the vendor directory. This makes Automatic Updates incompatible with some hosting platforms.
- The Composer executable must be in the PATH of the web server. If the Composer executable cannot be found the location can be set by adding
`$config['package_manager.settings']['executables']['composer'] = '/path/to/composer';` in `settings.php`
### Limitations
- Drupal multi-site installations are not supported.
- Automatic Updates does not support version control such as Git. It is the responsibility of site administrators to commit any updates to version control if needed.
Package Manager is a framework for updating Drupal core and installing contributed modules and themes via Composer. It has no user interface, but it provides an API for creating a temporary copy of the current site, making changes to the copy, and then syncing those changes back into the live site.
### Automatic Updates Initiative
Follow and read more on the [Automatic Updates Initiative overview and roadmap](https://www.drupal.org/project/ideas/issues/2940731).
### Updating contrib modules and themes
### Updating contributed modules and themes
Automatic Updates includes a sub-module, Automatic Updates Extensions, which supports updating contributed modules and themes.
⚠️ ☢️️ **Automatic Updates Extensions is still experimental and under heavy development.** We encourage you to test it in your local development environment, or another low-stakes testing situation, but it is emphatically NOT ready for use in a production environment. ☢️ ⚠️
⚠️ ☢️️ Depending on the contributed module or theme, updates to these projects could make the site inoperable. If possible, it is highly recommended that you test these updates in a development environment first.☢️ ⚠️
### Automatic Updates Initiative
### More info
- Follow and read up on
[Ideas queue - Automatic Updates initiative](https://www.drupal.org/project/ideas/issues/2940731)
Get more details about the Package Manager module, once installed, at it help page (`admin/help/package_manager`).
#!/usr/bin/env php
<?php
/**
* @file
* Provides a terminal command for performing automatic updates.
*/
use Drupal\automatic_updates\Commands\PostApplyCommand;
use Drupal\automatic_updates\Commands\RunCommand;
use Symfony\Component\Console\Application;
if (PHP_SAPI !== 'cli') {
throw new \RuntimeException('This command must be run from the command line.');
}
// Find the autoloader. We know that Automatic Updates is installed somewhere
// in a Drupal code base, so move up the file system until we find
// `./vendor/autoload.php`.
$current_dir = __DIR__;
$previous_dir = NULL;
while ($current_dir !== $previous_dir) {
$file = $current_dir . '/vendor/autoload.php';
if (file_exists($file)) {
/** @var \Composer\Autoload\ClassLoader $autoloader */
$autoloader = require_once $file;
break;
}
$previous_dir = $current_dir;
$current_dir = dirname($current_dir);
}
if (empty($autoloader)) {
throw new \RuntimeException('The autoloader could not be found. Did you run `composer install`?');
}
// Automatic Updates' namespace is not available for autoloading because it is
// a Drupal module, which means Drupal must be booted up in order to access it.
// Since Drupal isn't booted yet, we need to make the autoloader aware of the
// command namespace.
$autoloader->addPsr4('Drupal\\automatic_updates\\Commands\\', __DIR__ . '/src/Commands');
$application = new Application('Automatic Updates', '3.0.0');
$application->add(new RunCommand($autoloader));
$application->add(new PostApplyCommand($autoloader));
$application->setDefaultCommand('run')->run();
name: 'Automatic Updates'
type: module
description: 'Automatically updates Drupal core.'
core_version_requirement: ^9.3
core_version_requirement: ^10.1
dependencies:
- drupal:package_manager
- drupal:update
......@@ -5,13 +5,18 @@
* Contains install and update functions for Automatic Updates.
*/
use Drupal\automatic_updates\Validation\ReadinessRequirements;
declare(strict_types = 1);
use Drupal\automatic_updates\CronUpdateRunner;
use Drupal\automatic_updates\UpdateStage;
use Drupal\automatic_updates\Validation\StatusCheckRequirements;
use Drupal\system\SystemManager;
/**
* Implements hook_uninstall().
*/
function automatic_updates_uninstall() {
\Drupal::service('automatic_updates.updater')->destroy(TRUE);
\Drupal::service(UpdateStage::class)->destroy(TRUE);
}
/**
......@@ -20,8 +25,30 @@ function automatic_updates_uninstall() {
function automatic_updates_requirements($phase) {
if ($phase === 'runtime') {
// Check that site is ready to perform automatic updates.
/** @var \Drupal\automatic_updates\Validation\ReadinessRequirements $readiness_requirement */
$readiness_requirement = \Drupal::classResolver(ReadinessRequirements::class);
return $readiness_requirement->getRequirements();
/** @var \Drupal\automatic_updates\Validation\StatusCheckRequirements $status_check_requirement */
$status_check_requirement = \Drupal::classResolver(StatusCheckRequirements::class);
$requirements = $status_check_requirement->getRequirements();
// Check that site has cron updates enabled or not.
// @todo Remove in https://www.drupal.org/project/automatic_updates/issues/3284443
if (\Drupal::configFactory()->get('automatic_updates.settings')->get('unattended.level') !== CronUpdateRunner::DISABLED) {
$requirements['automatic_updates_cron'] = [
'title' => t('Cron installs updates automatically'),
'severity' => SystemManager::REQUIREMENT_WARNING,
'value' => t('Enabled. This is NOT an officially supported feature of the Automatic Updates module at this time. Use at your own risk.'),
];
}
return $requirements;
}
}
// BEGIN: DELETE FROM CORE MERGE REQUEST
/**
* Implements hook_update_last_removed().
*/
function automatic_updates_update_last_removed(): int {
return 9002;
}
// END: DELETE FROM CORE MERGE REQUEST
This diff is collapsed.
<?php
/**
* @file
* Contains post-update hooks for Automatic Updates.
*
* DELETE THIS FILE FROM CORE MERGE REQUEST.
*/
declare(strict_types = 1);
/**
* Implements hook_removed_post_updates().
*/
function automatic_updates_removed_post_updates(): array {
return [
'automatic_updates_post_update_create_status_check_mail_config' => '3.0.0',
];
}
automatic_updates.update_readiness:
path: '/admin/automatic_updates/readiness'
automatic_updates.status_check:
path: '/admin/automatic_updates/status'
defaults:
_controller: '\Drupal\automatic_updates\Controller\ReadinessCheckerController::run'
_controller: '\Drupal\automatic_updates\Controller\StatusCheckController::run'
_title: 'Update readiness checking'
requirements:
_permission: 'administer software updates'
options:
_maintenance_access: TRUE
_automatic_updates_readiness_messages: skip
_automatic_updates_status_messages: skip
automatic_updates.confirmation_page:
path: '/admin/automatic-update-ready/{stage_id}'
defaults:
......@@ -17,7 +17,7 @@ automatic_updates.confirmation_page:
_permission: 'administer software updates'
options:
_maintenance_access: TRUE
_automatic_updates_readiness_messages: skip
_automatic_updates_status_messages: skip
automatic_updates.finish:
path: '/automatic-update/finish'
defaults:
......@@ -26,45 +26,4 @@ automatic_updates.finish:
_permission: 'administer software updates'
options:
_maintenance_access: TRUE
_automatic_updates_readiness_messages: skip
automatic_updates.cron.post_apply:
path: '/automatic-update/cron/post-apply/{stage_id}/{installed_version}/{target_version}/{key}'
defaults:
_controller: 'automatic_updates.cron_updater:handlePostApply'
requirements:
_access_system_cron: 'TRUE'
# Links to our updater form appear in three different sets of local tasks. To ensure the breadcrumbs and paths are
# consistent with the other local tasks in each set, we need two separate routes to the same form.
automatic_updates.report_update:
path: '/admin/reports/updates/automatic-update'
defaults:
_form: '\Drupal\automatic_updates\Form\UpdaterForm'
_title: 'Update'
requirements:
_permission: 'administer software updates'
options:
_admin_route: TRUE
_maintenance_access: TRUE
_automatic_updates_readiness_messages: skip
automatic_updates.module_update:
path: '/admin/modules/automatic-update'
defaults:
_form: '\Drupal\automatic_updates\Form\UpdaterForm'
_title: 'Update'
requirements:
_permission: 'administer software updates'
options:
_admin_route: TRUE
_maintenance_access: TRUE
_automatic_updates_readiness_messages: skip
automatic_updates.theme_update:
path: '/admin/theme/automatic-update'
defaults:
_form: '\Drupal\automatic_updates\Form\UpdaterForm'
_title: 'Update'
requirements:
_permission: 'administer software updates'
options:
_admin_route: TRUE
_maintenance_access: TRUE
_automatic_updates_readiness_messages: skip
_automatic_updates_status_messages: skip
services:
automatic_updates.route_subscriber:
class: Drupal\automatic_updates\Routing\RouteSubscriber
_defaults:
autowire: true
Drupal\automatic_updates\Routing\RouteSubscriber:
tags:
- { name: event_subscriber }
automatic_updates.readiness_validation_manager:
class: Drupal\automatic_updates\Validation\ReadinessValidationManager
Drupal\automatic_updates\Validation\StatusChecker:
arguments:
- '@keyvalue.expirable'
- '@datetime.time'
- '@event_dispatcher'
- '@automatic_updates.updater'
- '@automatic_updates.cron_updater'
- 24
# @todo Remove this when https://drupal.org/i/3325557 lands.
$key_value_expirable_factory: '@keyvalue.expirable'
$resultsTimeToLive: 24
tags:
- { name: event_subscriber }
automatic_updates.updater:
class: Drupal\automatic_updates\Updater
arguments:
- '@config.factory'
- '@package_manager.path_locator'
- '@package_manager.beginner'
- '@package_manager.stager'
- '@package_manager.committer'
- '@file_system'
- '@event_dispatcher'
- '@tempstore.shared'
- '@datetime.time'
automatic_updates.cron_updater:
class: Drupal\automatic_updates\CronUpdater
arguments:
- '@automatic_updates.release_chooser'
- '@logger.factory'
- '@plugin.manager.mail'
- '@language_manager'
- '@state'
- '@config.factory'
- '@package_manager.path_locator'
- '@package_manager.beginner'
- '@package_manager.stager'
- '@package_manager.committer'
- '@file_system'
- '@event_dispatcher'
- '@tempstore.shared'
- '@datetime.time'
automatic_updates.staged_projects_validator:
class: Drupal\automatic_updates\Validator\StagedProjectsValidator
arguments:
- '@string_translation'
tags:
- { name: event_subscriber }
automatic_updates.release_chooser:
class: Drupal\automatic_updates\ReleaseChooser
arguments:
- '@automatic_updates.validator.version_policy'
automatic_updates.composer_executable_validator:
class: Drupal\automatic_updates\Validator\PackageManagerReadinessCheck
arguments:
- '@package_manager.validator.composer_executable'
tags:
- { name: event_subscriber }
automatic_updates.settings_validator:
class: Drupal\automatic_updates\Validator\PackageManagerReadinessCheck
arguments:
- '@package_manager.validator.settings'
tags:
- { name: event_subscriber }
automatic_updates.validator.composer_settings:
class: Drupal\automatic_updates\Validator\PackageManagerReadinessCheck
arguments:
- '@package_manager.validator.composer_settings'
tags:
- { name: event_subscriber }
automatic_updates.disk_space_validator:
class: Drupal\automatic_updates\Validator\PackageManagerReadinessCheck
arguments:
- '@package_manager.validator.disk_space'
tags:
- { name: event_subscriber }
automatic_updates.pending_updates_validator:
class: Drupal\automatic_updates\Validator\PackageManagerReadinessCheck
arguments:
- '@package_manager.validator.pending_updates'
Drupal\automatic_updates\StatusCheckMailer: ~
Drupal\automatic_updates\UpdateStage:
calls:
- ['setLogger', ['@logger.channel.automatic_updates']]
Drupal\automatic_updates\CronUpdateRunner:
calls:
- ['setLogger', ['@logger.channel.automatic_updates']]
decorates: 'cron'
Drupal\automatic_updates\Validator\RequestedUpdateValidator:
tags:
- { name: event_subscriber }
automatic_updates.validator.file_system_permissions:
class: Drupal\automatic_updates\Validator\PackageManagerReadinessCheck
arguments:
- '@package_manager.validator.file_system'
Drupal\automatic_updates\Validator\StagedProjectsValidator:
tags:
- { name: event_subscriber }
automatic_updates.validator.multisite:
class: Drupal\automatic_updates\Validator\PackageManagerReadinessCheck
Drupal\automatic_updates\ReleaseChooser: ~
Drupal\automatic_updates\Validator\CronFrequencyValidator:
arguments:
- '@package_manager.validator.multisite'
$lock: '@lock'
tags:
- { name: event_subscriber }
automatic_updates.validator.symlink:
class: Drupal\automatic_updates\Validator\PackageManagerReadinessCheck
arguments:
- '@package_manager.validator.symlink'
Drupal\automatic_updates\Validator\StagedDatabaseUpdateValidator:
tags:
- { name: event_subscriber }
automatic_updates.validator.patches:
class: Drupal\automatic_updates\Validator\PackageManagerReadinessCheck
arguments:
- '@package_manager.validator.patches'
Drupal\automatic_updates\Validator\VersionPolicyValidator:
tags:
- { name: event_subscriber }
automatic_updates.cron_frequency_validator:
class: Drupal\automatic_updates\Validator\CronFrequencyValidator
arguments:
- '@config.factory'
- '@module_handler'
- '@state'
- '@datetime.time'
- '@string_translation'
- '@automatic_updates.cron_updater'
Drupal\automatic_updates\Validator\WindowsValidator:
tags:
- { name: event_subscriber }
automatic_updates.validator.staged_database_updates:
class: Drupal\automatic_updates\Validator\StagedDatabaseUpdateValidator
logger.channel.automatic_updates:
parent: logger.channel_base
arguments: ['automatic_updates']
Drupal\automatic_updates\ConsoleUpdateStage:
arguments:
- '@package_manager.path_locator'
- '@extension.list.module'
- '@extension.list.theme'
- '@string_translation'
tags:
- { name: event_subscriber }
automatic_updates.validator.xdebug:
class: Drupal\automatic_updates\Validator\XdebugValidator
tags:
- { name: event_subscriber }
automatic_updates.validator.version_policy:
class: Drupal\automatic_updates\Validator\VersionPolicyValidator
arguments:
- '@class_resolver'
tags:
- { name: event_subscriber }
automatic_updates.config_subscriber:
class: Drupal\automatic_updates\EventSubscriber\ConfigSubscriber
$lock: '@lock'
$committer: '@Drupal\automatic_updates\MaintenanceModeAwareCommitter'
calls:
- ['setLogger', ['@logger.channel.automatic_updates']]
Drupal\automatic_updates\MaintenanceModeAwareCommitter:
tags:
- { name: event_subscriber }
automatic_updates.validator.scaffold_file_permissions:
class: Drupal\automatic_updates\Validator\ScaffoldFilePermissionsValidator
Drupal\automatic_updates\CommandExecutor:
arguments:
- '@package_manager.path_locator'
$appRoot: '%app.root%'
Drupal\automatic_updates\Validator\ConsoleUserValidator:
tags:
- { name: event_subscriber }
name: 'Automatic Updates Extensions'
type: module
description: 'Allows updates to themes and modules'
core_version_requirement: ^9.3
lifecycle: experimental
core_version_requirement: ^10.1
dependencies:
- drupal:automatic_updates
......@@ -7,7 +7,7 @@ automatic_updates_extensions.report_update:
_permission: 'administer software updates'
options:
_admin_route: TRUE
_automatic_updates_readiness_messages: skip
_automatic_updates_status_messages: skip
automatic_updates_extensions.module_update:
path: '/admin/modules/automatic-update-extensions'
......@@ -19,7 +19,7 @@ automatic_updates_extensions.module_update:
options:
_admin_route: TRUE
_maintenance_access: TRUE
_automatic_updates_readiness_messages: skip
_automatic_updates_status_messages: skip
automatic_updates_extension.theme_update:
path: '/admin/appearance/automatic-update-extensions'
......@@ -31,7 +31,7 @@ automatic_updates_extension.theme_update:
options:
_admin_route: TRUE
_maintenance_access: TRUE
_automatic_updates_readiness_messages: skip
_automatic_updates_status_messages: skip
automatic_updates_extension.confirmation_page:
path: '/admin/automatic-update-extensions-ready/{stage_id}'
......@@ -43,4 +43,4 @@ automatic_updates_extension.confirmation_page:
options:
_admin_route: TRUE
_maintenance_access: TRUE
_automatic_updates_readiness_messages: skip
_automatic_updates_status_messages: skip
services:
automatic_updates_extensions.updater:
class: Drupal\automatic_updates_extensions\ExtensionUpdater
arguments:
- '@config.factory'
- '@package_manager.path_locator'
- '@package_manager.beginner'
- '@package_manager.stager'
- '@package_manager.committer'
- '@file_system'
- '@event_dispatcher'
- '@tempstore.shared'
- '@datetime.time'
automatic_updates_extensions.validator.packages_installed_with_composer:
class: Drupal\automatic_updates_extensions\Validator\PackagesInstalledWithComposerValidator
arguments:
- '@string_translation'
_defaults:
autowire: true
Drupal\automatic_updates_extensions\ExtensionUpdateStage: ~
Drupal\automatic_updates_extensions\Validator\UpdateReleaseValidator:
tags:
- { name: event_subscriber }
automatic_updates_extensions.validator.packages_type:
class: Drupal\automatic_updates_extensions\Validator\UpdatePackagesTypeValidator
arguments:
- '@string_translation'
- '@extension.list.module'
- '@extension.list.theme'
Drupal\automatic_updates_extensions\Validator\ForbidCoreChangesValidator:
tags:
- { name: event_subscriber }
automatic_updates_extensions.validator.target_release:
class: Drupal\automatic_updates_extensions\Validator\UpdateReleaseValidator
Drupal\automatic_updates_extensions\Validator\RequestedUpdateValidator:
tags:
- { name: event_subscriber }
<?php
declare(strict_types = 1);
namespace Drupal\automatic_updates_extensions;
use Drupal\Core\Url;
use Drupal\package_manager\Exception\StageValidationException;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
......@@ -23,13 +24,13 @@ final class BatchProcessor {
public const STAGE_ID_SESSION_KEY = '_automatic_updates_extensions_stage_id';
/**
* Gets the updater service.
* Gets the update stage service.
*
* @return \Drupal\automatic_updates_extensions\ExtensionUpdater
* The updater service.
* @return \Drupal\automatic_updates_extensions\ExtensionUpdateStage
* The update stage service.
*/
protected static function getUpdater(): ExtensionUpdater {
return \Drupal::service('automatic_updates_extensions.updater');
private static function getStage(): ExtensionUpdateStage {
return \Drupal::service(ExtensionUpdateStage::class);
}
/**
......@@ -44,40 +45,24 @@ final class BatchProcessor {
* The caught exception, which will always be re-thrown once its messages
* have been recorded.
*/
protected static function handleException(\Throwable $error, array &$context): void {
$error_messages = [
$error->getMessage(),
];
if ($error instanceof StageValidationException) {
foreach ($error->getResults() as $result) {
$messages = $result->getMessages();
if (count($messages) > 1) {
array_unshift($messages, $result->getSummary());
}
$error_messages = array_merge($error_messages, $messages);
}
}
foreach ($error_messages as $error_message) {
$context['results']['errors'][] = $error_message;
}
private static function handleException(\Throwable $error, array &$context): void {
$context['results']['errors'][] = $error->getMessage();
throw $error;
}
/**
* Calls the updater's begin() method.
* Calls the update stage's begin() method.
*
* @param string[] $project_versions
* The project versions to be staged in the update, keyed by package name.
* @param array $context
* The current context of the batch job.
*
* @see \Drupal\automatic_updates_extensions\ExtensionUpdater::begin()
* @see \Drupal\automatic_updates_extensions\ExtensionUpdateStage::begin()
*/
public static function begin(array $project_versions, array &$context): void {
try {
$stage_id = static::getUpdater()->begin($project_versions);
$stage_id = static::getStage()->begin($project_versions);
\Drupal::service('session')->set(static::STAGE_ID_SESSION_KEY, $stage_id);
}
catch (\Throwable $e) {
......@@ -86,37 +71,50 @@ final class BatchProcessor {
}
/**
* Calls the updater's stageVersions() method.
* Calls the update stage's stage() method.
*
* @param array $context
* The current context of the batch job.
*
* @see \Drupal\automatic_updates\Updater::stage()
* @see \Drupal\automatic_updates\UpdateStage::stage()
*/
public static function stage(array &$context): void {
$stage_id = \Drupal::service('session')->get(static::STAGE_ID_SESSION_KEY);
try {
$stage_id = \Drupal::service('session')->get(static::STAGE_ID_SESSION_KEY);
static::getUpdater()->claim($stage_id)->stage();
static::getStage()->claim($stage_id)->stage();
}
catch (\Throwable $e) {
static::clean($stage_id, $context);
// If the stage was not already destroyed because of this exception
// destroy it.
if (!static::getStage()->isAvailable()) {
static::clean($stage_id, $context);
}
static::handleException($e, $context);
}
}
/**
* Calls the updater's commit() method.
* Calls the update stage's apply() method.
*
* @param string $stage_id
* The stage ID.
* @param array $context
* The current context of the batch job.
*
* @see \Drupal\automatic_updates\Updater::apply()
* @see \Drupal\automatic_updates_extensions\ExtensionUpdateStage::apply()
*/
public static function commit(string $stage_id, array &$context): void {
try {
static::getUpdater()->claim($stage_id)->apply();
static::getStage()->claim($stage_id)->apply();
// The batch system does not allow any single request to run for longer
// than a second, so this will force the next operation to be done in a
// new request. This helps keep the running code in as consistent a state
// as possible.
// @see \Drupal\package_manager\Stage::apply()
// @see \Drupal\package_manager\Stage::postApply()
// @todo See if there's a better way to ensure the post-apply tasks run
// in a new request in https://www.drupal.org/i/3293150.
sleep(1);
}
catch (\Throwable $e) {
static::handleException($e, $context);
......@@ -124,18 +122,18 @@ final class BatchProcessor {
}
/**
* Calls the updater's postApply() method.
* Calls the update stage's postApply() method.
*
* @param string $stage_id
* The stage ID.
* @param array $context
* The current context of the batch job.
*
* @see \Drupal\automatic_updates\Updater::postApply()
* @see \Drupal\automatic_updates\UpdateStage::postApply()
*/
public static function postApply(string $stage_id, array &$context): void {
try {
static::getUpdater()->claim($stage_id)->postApply();
static::getStage()->claim($stage_id)->postApply();
}
catch (\Throwable $e) {
static::handleException($e, $context);
......@@ -143,18 +141,18 @@ final class BatchProcessor {
}
/**
* Calls the updater's clean() method.
* Calls the update stage's destroy() method.
*
* @param string $stage_id
* The stage ID.
* @param array $context
* The current context of the batch job.
*
* @see \Drupal\automatic_updates\Updater::clean()
* @see \Drupal\automatic_updates_extensions\ExtensionUpdateStage::destroy()
*/
public static function clean(string $stage_id, array &$context): void {
try {
static::getUpdater()->claim($stage_id)->destroy();
static::getStage()->claim($stage_id)->destroy();
}
catch (\Throwable $e) {
static::handleException($e, $context);
......@@ -212,7 +210,7 @@ final class BatchProcessor {
* @param array $results
* The batch results.
*/
protected static function handleBatchError(array $results): void {
private static function handleBatchError(array $results): void {
if (isset($results['errors'])) {
foreach ($results['errors'] as $error) {
\Drupal::messenger()->addError($error);
......
<?php
declare(strict_types = 1);
namespace Drupal\automatic_updates_extensions;
use Drupal\automatic_updates\Exception\UpdateException;
use Drupal\automatic_updates\LegacyVersionUtility;
use Drupal\package_manager\Event\StageEvent;
use Drupal\package_manager\Exception\StageValidationException;
use Drupal\package_manager\Stage;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Queue\QueueFactory;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\TempStore\SharedTempStoreFactory;
use Drupal\package_manager\ComposerInspector;
use Drupal\package_manager\FailureMarker;
use Drupal\package_manager\LegacyVersionUtility;
use Drupal\package_manager\PathLocator;
use Drupal\package_manager\StageBase;
use PhpTuf\ComposerStager\API\Core\BeginnerInterface;
use PhpTuf\ComposerStager\API\Core\CommitterInterface;
use PhpTuf\ComposerStager\API\Core\StagerInterface;
use PhpTuf\ComposerStager\API\Path\Factory\PathFactoryInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
/**
* Defines a service to perform updates for modules and themes.
......@@ -15,7 +26,54 @@ use Drupal\package_manager\Stage;
* This class is an internal part of the module's update handling and
* should not be used by external code.
*/
class ExtensionUpdater extends Stage {
final class ExtensionUpdateStage extends StageBase {
/**
* {@inheritdoc}
*/
protected string $type = 'automatic_updates_extensions:attended';
/**
* Constructs a new ExtensionUpdateStage object.
*
* @param \Drupal\package_manager\ComposerInspector $composerInspector
* The Composer inspector service.
* @param \Drupal\package_manager\PathLocator $pathLocator
* The path locator service.
* @param \PhpTuf\ComposerStager\API\Core\BeginnerInterface $beginner
* The beginner service.
* @param \PhpTuf\ComposerStager\API\Core\StagerInterface $stager
* The stager service.
* @param \PhpTuf\ComposerStager\API\Core\CommitterInterface $committer
* The committer service.
* @param \Drupal\Core\Queue\QueueFactory $queueFactory
* The queue factory.
* @param \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $eventDispatcher
* The event dispatcher service.
* @param \Drupal\Core\TempStore\SharedTempStoreFactory $tempStoreFactory
* The shared tempstore factory.
* @param \Drupal\Component\Datetime\TimeInterface $time
* The time service.
* @param \PhpTuf\ComposerStager\API\Path\Factory\PathFactoryInterface $pathFactory
* The path factory service.
* @param \Drupal\package_manager\FailureMarker $failureMarker
* The failure marker service.
*/
public function __construct(
protected readonly ComposerInspector $composerInspector,
PathLocator $pathLocator,
BeginnerInterface $beginner,
StagerInterface $stager,
CommitterInterface $committer,
QueueFactory $queueFactory,
EventDispatcherInterface $eventDispatcher,
SharedTempStoreFactory $tempStoreFactory,
TimeInterface $time,
PathFactoryInterface $pathFactory,
FailureMarker $failureMarker,
) {
parent::__construct($pathLocator, $beginner, $stager, $committer, $queueFactory, $eventDispatcher, $tempStoreFactory, $time, $pathFactory, $failureMarker);
}
/**
* Begins the update.
......@@ -33,19 +91,27 @@ class ExtensionUpdater extends Stage {
if (empty($project_versions)) {
throw new \InvalidArgumentException("No projects to begin the update");
}
$composer = $this->getActiveComposer();
$package_versions = [
'production' => [],
'dev' => [],
];
$require_dev = $composer->getComposer()
->getPackage()
->getDevRequires();
$project_root = $this->pathLocator->getProjectRoot();
$info = $this->composerInspector->getRootPackageInfo($project_root);
$installed_packages = $this->composerInspector->getInstalledPackagesList($project_root);
foreach ($project_versions as $project_name => $version) {
$package = "drupal/$project_name";
$group = array_key_exists($package, $require_dev) ? 'dev' : 'production';
$package_versions[$group][$package] = LegacyVersionUtility::convertToSemanticVersion($version);
$package = $installed_packages->getPackageByDrupalProjectName($project_name);
if (empty($package)) {
throw new \InvalidArgumentException("The project $project_name is not a Drupal project known to Composer and cannot be updated.");
}
// We don't support updating install profiles.
if ($package->type === 'drupal-profile') {
throw new \InvalidArgumentException("The project $project_name cannot be updated because updating install profiles is not supported.");
}
$group = isset($info['devRequires'][$package->name]) ? 'dev' : 'production';
$package_versions[$group][$package->name] = LegacyVersionUtility::convertToSemanticVersion($version);
}
// Ensure that package versions are available to pre-create event
......@@ -91,13 +157,8 @@ class ExtensionUpdater extends Stage {
/**
* {@inheritdoc}
*/
protected function dispatch(StageEvent $event, callable $on_error = NULL): void {
try {
parent::dispatch($event, $on_error);
}
catch (StageValidationException $e) {
throw new UpdateException($e->getResults(), $e->getMessage() ?: "Unable to complete the update because of errors.", $e->getCode(), $e);
}
protected function getFailureMarkerMessage(): TranslatableMarkup {
return $this->t('Automatic updates failed to apply, and the site is in an indeterminate state. Consider restoring the code and database from a backup.');
}
}
<?php
declare(strict_types = 1);
namespace Drupal\automatic_updates_extensions\Form;
use Drupal\automatic_updates\Validator\StagedDatabaseUpdateValidator;
use Drupal\automatic_updates\Form\UpdateFormBase;
use Drupal\package_manager\ComposerInspector;
use Drupal\package_manager\Exception\StageFailureMarkerException;
use Drupal\package_manager\InstalledPackage;
use Drupal\package_manager\PathLocator;
use Drupal\package_manager\ProjectInfo;
use Drupal\package_manager\ValidationResult;
use Drupal\automatic_updates_extensions\BatchProcessor;
use Drupal\automatic_updates\BatchProcessor as AutoUpdatesBatchProcessor;
use Drupal\automatic_updates_extensions\ExtensionUpdater;
use Drupal\automatic_updates_extensions\ExtensionUpdateStage;
use Drupal\Core\Batch\BatchBuilder;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\package_manager\Exception\StageException;
use Drupal\package_manager\Exception\StageOwnershipException;
use Drupal\system\SystemManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* Defines a form to commit staged updates.
*
* @internal
* Form classes are internal.
* Form classes are internal and should not be used by external code.
*/
final class UpdateReady extends FormBase {
/**
* The updater service.
*
* @var \Drupal\automatic_updates_extensions\ExtensionUpdater
*/
protected $updater;
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* The module list service.
*
* @var \Drupal\Core\Extension\ModuleExtensionList
*/
protected $moduleList;
/**
* The staged database update validator service.
*
* @var \Drupal\automatic_updates\Validator\StagedDatabaseUpdateValidator
*/
protected $stagedDatabaseUpdateValidator;
final class UpdateReady extends UpdateFormBase {
/**
* Constructs a new UpdateReady object.
*
* @param \Drupal\automatic_updates_extensions\ExtensionUpdater $updater
* The updater service.
* @param \Drupal\automatic_updates_extensions\ExtensionUpdateStage $stage
* The update stage service.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger service.
* @param \Drupal\Core\State\StateInterface $state
* The state service.
* @param \Drupal\Core\Extension\ModuleExtensionList $module_list
* @param \Drupal\Core\Extension\ModuleExtensionList $moduleList
* The module list service.
* @param \Drupal\automatic_updates\Validator\StagedDatabaseUpdateValidator $staged_database_update_validator
* The staged database update validator service.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer service.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher
* Event dispatcher service.
* @param \Drupal\package_manager\ComposerInspector $composerInspector
* The Composer inspector service.
* @param \Drupal\package_manager\PathLocator $pathLocator
* The path locator service.
*/
public function __construct(ExtensionUpdater $updater, MessengerInterface $messenger, StateInterface $state, ModuleExtensionList $module_list, StagedDatabaseUpdateValidator $staged_database_update_validator) {
$this->updater = $updater;
public function __construct(
private readonly ExtensionUpdateStage $stage,
MessengerInterface $messenger,
private readonly StateInterface $state,
private readonly ModuleExtensionList $moduleList,
private readonly RendererInterface $renderer,
private readonly EventDispatcherInterface $eventDispatcher,
private readonly ComposerInspector $composerInspector,
private readonly PathLocator $pathLocator,
) {
$this->setMessenger($messenger);
$this->state = $state;
$this->moduleList = $module_list;
$this->stagedDatabaseUpdateValidator = $staged_database_update_validator;
}
/**
......@@ -86,11 +80,14 @@ final class UpdateReady extends FormBase {
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('automatic_updates_extensions.updater'),
$container->get(ExtensionUpdateStage::class),
$container->get('messenger'),
$container->get('state'),
$container->get('extension.list.module'),
$container->get('automatic_updates.validator.staged_database_updates')
$container->get('renderer'),
$container->get('event_dispatcher'),
$container->get(ComposerInspector::class),
$container->get(PathLocator::class),
);
}
......@@ -99,26 +96,19 @@ final class UpdateReady extends FormBase {
*/
public function buildForm(array $form, FormStateInterface $form_state, string $stage_id = NULL) {
try {
$this->updater->claim($stage_id);
$this->stage->claim($stage_id);
}
catch (StageOwnershipException $e) {
catch (StageOwnershipException) {
$this->messenger()->addError($this->t('Cannot continue the update because another Composer operation is currently in progress.'));
return $form;
}
catch (StageFailureMarkerException $e) {
$this->messenger()->addError($e->getMessage());
return $form;
}
$messages = [];
// If there are any installed extension with database updates in the staging
// area, warn the user that they might be sent to update.php once the staged
// changes have been applied.
$pending_updates = $this->stagedDatabaseUpdateValidator->getExtensionsWithDatabaseUpdates($this->updater);
if ($pending_updates) {
$messages[MessengerInterface::TYPE_WARNING][] = $this->t('Possible database updates were detected in the following extensions; you may be redirected to the database update page in order to complete the update process.');
foreach ($pending_updates as $pending_update) {
$messages[MessengerInterface::TYPE_WARNING][] = $pending_update;
}
}
// Don't set any messages if the form has been submitted, because we don't
// want them to be set during form submit.
if (!$form_state->getUserInput()) {
......@@ -141,12 +131,14 @@ final class UpdateReady extends FormBase {
'#type' => 'value',
'#value' => $stage_id,
];
// @todo Display the project versions that will be update including any
// dependencies that are Drupal projects.
$form['package_updates'] = $this->showUpdates();
$form['backup'] = [
'#prefix' => '<strong>',
'#markup' => $this->t('Back up your database and site before you continue. <a href=":backup_url">Learn how</a>.', [':backup_url' => 'https://www.drupal.org/node/22281']),
'#type' => 'checkbox',
'#title' => $this->t('Warning: Updating contributed modules or themes may leave your site inoperable or looking wrong.'),
'#description' => $this->t('Back up your database and site before you continue. <a href=":backup_url">Learn how</a>. Each contributed module or theme may follow different standards for backwards compatibility, may or may not have tests, and may add or remove features in any release. For these reasons, it is highly recommended that you test this update in a development environment first.', [':backup_url' => 'https://www.drupal.org/node/22281']),
'#required' => TRUE,
'#default_value' => FALSE,
'#suffix' => '</strong>',
];
$form['maintenance_mode'] = [
......@@ -154,6 +146,18 @@ final class UpdateReady extends FormBase {
'#type' => 'checkbox',
'#default_value' => TRUE,
];
// Don't run the status checks once the form has been submitted.
if (!$form_state->getUserInput()) {
$results = $this->runStatusCheck($this->stage, $this->eventDispatcher);
// This will have no effect if $results is empty.
$this->displayResults($results, $this->renderer);
// If any errors occurred, return the form early so the user cannot
// continue.
if (ValidationResult::getOverallSeverity($results) === SystemManager::REQUIREMENT_ERROR) {
return $form;
}
}
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Continue'),
......@@ -192,7 +196,7 @@ final class UpdateReady extends FormBase {
*/
public function cancel(array &$form, FormStateInterface $form_state): void {
try {
$this->updater->destroy();
$this->stage->destroy();
$this->messenger()->addStatus($this->t('The update was successfully cancelled.'));
$form_state->setRedirect('automatic_updates_extensions.report_update');
}
......@@ -201,4 +205,115 @@ final class UpdateReady extends FormBase {
}
}
/**
* Displays all projects that will be updated.
*
* @return mixed[][]
* A render array displaying packages that will be updated.
*/
private function showUpdates(): array {
// Get packages that were updated in the stage directory.
$installed_packages = $this->composerInspector->getInstalledPackagesList($this->pathLocator->getProjectRoot());
$staged_packages = $this->composerInspector->getInstalledPackagesList($this->stage->getStageDirectory());
$updated_packages = $staged_packages->getPackagesWithDifferentVersionsIn($installed_packages);
// Build a list of package names that were updated by user request.
$updated_by_request = [];
foreach ($this->stage->getPackageVersions() as $group) {
$updated_by_request = array_merge($updated_by_request, array_keys($group));
}
$updated_by_request_info = [];
$updated_project_info = [];
$supported_package_types = ['drupal-module', 'drupal-theme'];
// Compile an array of relevant information about the packages that will be
// updated.
foreach ($updated_packages as $name => $updated_package) {
// Ignore anything that isn't a module or a theme.
if (!in_array($updated_package->type, $supported_package_types, TRUE)) {
continue;
}
$updated_project_info[$name] = [
'title' => $this->getProjectTitleFromPackage($updated_package),
'installed_version' => $installed_packages[$updated_package->name]->version,
'updated_version' => $updated_package->version,
];
}
foreach ($updated_packages as $name => $updated_package) {
// Sort the updated packages into two groups: the ones that were updated
// at the request of the user, and the ones that got updated anyway
// (probably due to Composer's dependency resolution).
if (in_array($name, $updated_by_request, TRUE)) {
$updated_by_request_info[$name] = $updated_project_info[$name];
unset($updated_project_info[$name]);
}
}
$output = [];
if ($updated_by_request_info) {
// Create the list of messages for the packages updated by request.
$output['requested'] = $this->getUpdatedPackagesItemList($updated_by_request_info, $this->t('The following projects will be updated:'));
}
if ($updated_project_info) {
// Create the list of messages for packages that were updated
// incidentally.
$output['dependencies'] = $this->getUpdatedPackagesItemList($updated_project_info, $this->t('The following dependencies will also be updated:'));
}
return $output;
}
/**
* Gets the human-readable project title for a Composer package.
*
* @param \Drupal\package_manager\InstalledPackage $package
* The installed package.
*
* @return string
* The human-readable title of the project. If no project information is
* available, the package name is returned.
*/
private function getProjectTitleFromPackage(InstalledPackage $package): string {
$project_name = $package->getProjectName();
if (!$project_name) {
return $package->name;
}
$project_info = new ProjectInfo($project_name);
$project_data = $project_info->getProjectInfo();
if ($project_data) {
return $project_data['title'];
}
else {
return $package->name;
}
}
/**
* Generates an item list of packages that will be updated.
*
* @param array[] $updated_packages
* An array of packages that will be updated, each sub-array containing the
* project title, installed version, and target version.
* @param \Drupal\Core\StringTranslation\TranslatableMarkup $item_list_title
* The title of the generated item list.
*
* @return array
* A render array for the generated item list.
*/
private function getUpdatedPackagesItemList(array $updated_packages, TranslatableMarkup $item_list_title): array {
$create_message_for_project = function (array $project): TranslatableMarkup {
return $this->t('@title from @from_version to @to_version', [
'@title' => $project['title'],
'@from_version' => $project['installed_version'],
'@to_version' => $project['updated_version'],
]);
};
return [
'#theme' => 'item_list',
'#prefix' => '<p>' . $item_list_title . '</p>',
'#items' => array_map($create_message_for_project, $updated_packages),
];
}
}
<?php
declare(strict_types = 1);
namespace Drupal\automatic_updates_extensions\Form;
use Drupal\automatic_updates\Event\ReadinessCheckEvent;
use Drupal\automatic_updates\Validation\ReadinessTrait;
use Drupal\automatic_updates\Form\UpdateFormBase;
use Drupal\automatic_updates_extensions\BatchProcessor;
use Drupal\automatic_updates_extensions\ExtensionUpdater;
use Drupal\automatic_updates_extensions\ExtensionUpdateStage;
use Drupal\Core\Batch\BatchBuilder;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Url;
use Drupal\package_manager\ComposerInspector;
use Drupal\package_manager\Exception\StageFailureMarkerException;
use Drupal\package_manager\FailureMarker;
use Drupal\package_manager\PathLocator;
use Drupal\package_manager\ProjectInfo;
use Drupal\package_manager\ValidationResult;
use Drupal\system\SystemManager;
use Drupal\update\ProjectRelease;
use Drupal\update\UpdateManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
......@@ -22,70 +29,52 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
* A form for selecting extension updates.
*
* @internal
* Form classes are internal.
* Form classes are internal and should not be used by external code.
*/
final class UpdaterForm extends FormBase {
use ReadinessTrait;
/**
* The extension updater service.
*
* @var \Drupal\automatic_updates_extensions\ExtensionUpdater
*/
private $extensionUpdater;
/**
* The event dispatcher service.
*
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/
private $eventDispatcher;
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
private $state;
/**
* The renderer service.
*
* @var \Drupal\Core\Render\RendererInterface
*/
private $renderer;
final class UpdaterForm extends UpdateFormBase {
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('automatic_updates_extensions.updater'),
$container->get(ExtensionUpdateStage::class),
$container->get('event_dispatcher'),
$container->get('renderer'),
$container->get('state')
$container->get('state'),
$container->get(FailureMarker::class),
$container->get(ComposerInspector::class),
$container->get(PathLocator::class),
);
}
/**
* Constructs a new UpdaterForm object.
*
* @param \Drupal\automatic_updates_extensions\ExtensionUpdater $extension_updater
* The extension updater service.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
* @param \Drupal\automatic_updates_extensions\ExtensionUpdateStage $stage
* The extension update stage service.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher
* The extension event dispatcher service.
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer service.
* @param \Drupal\Core\State\StateInterface $state
* The state service.
* @param \Drupal\package_manager\FailureMarker $failureMarker
* The failure marker service.
* @param \Drupal\package_manager\ComposerInspector $composerInspector
* The Composer inspector service.
* @param \Drupal\package_manager\PathLocator $pathLocator
* The path locator service.
*/
public function __construct(ExtensionUpdater $extension_updater, EventDispatcherInterface $event_dispatcher, RendererInterface $renderer, StateInterface $state) {
$this->extensionUpdater = $extension_updater;
$this->eventDispatcher = $event_dispatcher;
$this->renderer = $renderer;
$this->state = $state;
}
public function __construct(
private readonly ExtensionUpdateStage $stage,
private readonly EventDispatcherInterface $eventDispatcher,
private readonly RendererInterface $renderer,
private readonly StateInterface $state,
private readonly FailureMarker $failureMarker,
private readonly ComposerInspector $composerInspector,
private readonly PathLocator $pathLocator,
) {}
/**
* {@inheritdoc}
......@@ -98,6 +87,13 @@ final class UpdaterForm extends FormBase {
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
try {
$this->failureMarker->assertNotExists();
}
catch (StageFailureMarkerException $e) {
$this->messenger()->addError($e->getMessage());
return $form;
}
$update_projects = $this->getRecommendedModuleUpdates();
$options = [];
$recommended_versions = [];
......@@ -115,10 +111,16 @@ final class UpdaterForm extends FormBase {
default:
$status_message = '';
}
$project_release = ProjectRelease::createFromArray($update_project['releases'][$update_project['recommended']]);
$options[$project_name] = [
$update_project['title'] . $status_message,
$update_project['existing_version'],
$update_project['recommended'],
$this->t(
'@version (<a href=":url">Release notes</a>)',
[
'@version' => $project_release->getVersion(),
':url' => $project_release->getReleaseUrl(),
]),
];
$recommended_versions[$project_name] = $update_project['recommended'];
}
......@@ -137,19 +139,17 @@ final class UpdaterForm extends FormBase {
'#empty' => $this->t('There are no available updates.'),
'#attributes' => ['class' => ['update-recommended']],
'#required' => TRUE,
'#required_error' => t('Please select one or more projects.'),
'#required_error' => t('Select one or more projects.'),
];
if ($form_state->getUserInput()) {
$results = [];
}
else {
$event = new ReadinessCheckEvent($this->extensionUpdater);
$this->eventDispatcher->dispatch($event);
$results = $event->getResults();
$results = $this->runStatusCheck($this->stage, $this->eventDispatcher);
}
$this->displayResults($results, $this->messenger(), $this->renderer);
$security_level = $this->getOverallSeverity($results);
$this->displayResults($results, $this->renderer);
$security_level = ValidationResult::getOverallSeverity($results);
if ($update_projects && $security_level !== SystemManager::REQUIREMENT_ERROR) {
$form['actions'] = $this->actions($form_state);
......@@ -171,9 +171,9 @@ final class UpdaterForm extends FormBase {
* @return mixed[][]
* The form's actions elements.
*/
protected function actions(FormStateInterface $form_state): array {
private function actions(FormStateInterface $form_state): array {
$actions = ['#type' => 'actions'];
if (!$this->extensionUpdater->isAvailable()) {
if (!$this->stage->isAvailable()) {
// If the form has been submitted do not display this error message
// because ::deleteExistingUpdate() may run on submit. The message will
// still be displayed on form build if needed.
......@@ -199,7 +199,7 @@ final class UpdaterForm extends FormBase {
* Submit function to delete an existing in-progress update.
*/
public function deleteExistingUpdate(): void {
$this->extensionUpdater->destroy(TRUE);
$this->stage->destroy(TRUE);
$this->messenger()->addMessage($this->t("Staged update deleted"));
}
......@@ -232,28 +232,33 @@ final class UpdaterForm extends FormBase {
* Modules that require updates.
*/
private function getRecommendedModuleUpdates(): array {
$supported_project_types = [
"module", "module-disabled", "theme", "theme-disabled",
];
$available_updates = update_get_available(TRUE);
if (empty($available_updates)) {
$this->messenger()->addError('There was a problem getting update information. Try again later.');
return [];
}
$project_data = update_calculate_project_data($available_updates);
$all_projects_data = update_calculate_project_data($available_updates);
$outdated_modules = [];
$installed_packages = array_keys($this->extensionUpdater->getActiveComposer()->getInstalledPackages());
$installed_packages = $this->composerInspector->getInstalledPackagesList($this->pathLocator->getProjectRoot());
$non_supported_update_statuses = [];
foreach ($project_data as $project_name => $project_info) {
if ($project_info['project_type'] === 'module' || $project_info['project_type'] === 'module-disabled') {
if ($project_info['status'] !== UpdateManagerInterface::CURRENT) {
if (!in_array("drupal/$project_name", $installed_packages, TRUE)) {
$non_supported_update_statuses[] = $project_info['status'];
foreach ($all_projects_data as $project_name => $project_data) {
if (in_array($project_data['project_type'], $supported_project_types, TRUE)) {
if ($project_data['status'] !== UpdateManagerInterface::CURRENT) {
if ($installed_packages->getPackageByDrupalProjectName($project_name) === NULL) {
$non_supported_update_statuses[] = $project_data['status'];
continue;
}
if (!empty($project_info['recommended'])) {
$outdated_modules[$project_name] = $project_info;
$project_information = new ProjectInfo($project_name);
$installable_versions = array_keys($project_information->getInstallableReleases());
if (!empty($project_data['recommended']) && in_array($project_data['recommended'], $installable_versions, TRUE)) {
$outdated_modules[$project_name] = $project_data;
}
else {
$non_supported_update_statuses[] = $project_info['status'];
$non_supported_update_statuses[] = $project_data['status'];
}
}
}
......@@ -284,7 +289,6 @@ final class UpdaterForm extends FormBase {
$message_status
);
}
}
return $outdated_modules;
}
......