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
Showing
with 1792 additions and 26 deletions
<?php
declare(strict_types = 1);
namespace Drupal\Tests\automatic_updates_extensions\Build;
use Drupal\Tests\automatic_updates\Build\UpdateTestBase;
use Drupal\Tests\automatic_updates_extensions\Traits\FormTestTrait;
use Symfony\Component\Filesystem\Filesystem as SymfonyFilesystem;
/**
* Tests updating modules in a stage directory.
*
* @group automatic_updates_extensions
* @internal
*/
final class ModuleUpdateTest extends UpdateTestBase {
use FormTestTrait;
/**
* {@inheritdoc}
*/
protected function createTestProject(string $template): void {
parent::createTestProject($template);
$this->setReleaseMetadata([
'drupal' => __DIR__ . '/../../../../package_manager/tests/fixtures/release-history/drupal.9.8.2.xml',
'alpha' => __DIR__ . '/../../fixtures/release-history/alpha.1.1.0.xml',
'new_module' => __DIR__ . '/../../fixtures/release-history/new_module.1.1.0.xml',
]);
// Set 'version' and 'project' for the 'alpha' and 'new_module' module to
// enable the Update to determine the update status.
$system_info = [
'alpha' => ['version' => '1.0.0', 'project' => 'alpha'],
'new_module' => ['version' => '1.0.0', 'project' => 'new_module'],
];
$system_info = var_export($system_info, TRUE);
$code = <<<END
\$config['update_test.settings']['system_info'] = $system_info;
END;
$this->writeSettings($code);
$alpha_repo_path = $this->copyFixtureToTempDirectory(__DIR__ . '/../../../../package_manager/tests/fixtures/build_test_projects/alpha/1.0.0');
$this->addRepository('alpha', $alpha_repo_path);
$this->runComposer('composer require drupal/alpha --update-with-all-dependencies', 'project');
$this->assertModuleVersion('alpha', '1.0.0');
$fs = new SymfonyFilesystem();
$fs->mirror($this->copyFixtureToTempDirectory(__DIR__ . '/../../fixtures/new_module'), $this->getWorkspaceDirectory() . '/project/web/modules');
$this->installModules([
'automatic_updates_extensions_test_api',
'alpha',
'new_module',
]);
// Change the module's upstream version.
static::copyFixtureFilesTo(__DIR__ . '/../../../../package_manager/tests/fixtures/build_test_projects/alpha/1.1.0', $alpha_repo_path);
// Ensure that none of the above changes have caused any status check or
// other errors on the status report.
$this->checkForUpdates();
$this->assertStatusReportChecksSuccessful();
}
/**
* Tests updating a module in a stage directory via the API.
*/
public function testApi(): void {
$this->createTestProject('RecommendedProject');
// Use the API endpoint to create a stage and update the 'new_module' module
// to 1.1.0.
// @see \Drupal\automatic_updates_extensions_test_api\ApiController::run()
$query = http_build_query([
'projects' => [
'new_module' => '1.1.0',
],
]);
$this->visit("/automatic-updates-extensions-test-api?$query");
$mink = $this->getMink();
$mink->assertSession()->statusCodeEquals(500);
$page_text = $mink->getSession()->getPage()->getText();
$this->assertStringContainsString('The project new_module is not a Drupal project known to Composer and cannot be updated.', $page_text);
$this->assertStringContainsString('new_module', $page_text);
// Use the API endpoint to create a stage and update the 'alpha' module to
// 1.1.0.
$this->makePackageManagerTestApiRequest(
'/automatic-updates-extensions-test-api',
[
'projects' => [
'alpha' => '1.1.0',
],
]
);
$updated_composer_json = $this->getWebRoot() . 'modules/contrib/alpha/composer.json';
// Assert the module was updated.
$this->assertFileEquals(
__DIR__ . '/../../../../package_manager/tests/fixtures/build_test_projects/alpha/1.1.0/composer.json',
$updated_composer_json,
);
$this->assertRequestedChangesWereLogged(['Update drupal/alpha from 1.0.0 to 1.1.0']);
$this->assertAppliedChangesWereLogged(['Updated drupal/alpha from 1.0.0 to 1.1.0']);
}
/**
* Tests updating a module in a stage directory via the UI.
*/
public function testUi(): void {
$this->createTestProject('RecommendedProject');
$mink = $this->getMink();
$session = $mink->getSession();
$page = $session->getPage();
$assert_session = $mink->assertSession();
$this->visit('/admin/reports/updates');
// Confirm that 'New Module' project, which is not installed via Composer,
// has a 1.1.0 update release on the 'Available Updates' page.
$this->assertReportProjectUpdateVersion('New Module', '1.1.0');
$page->clickLink('Update Extensions');
$this->assertUpdateTableRow($assert_session, 'Alpha', '1.0.0', '1.1.0', 1);
// Confirm that a 'New Module' project does not appear on the form.
$assert_session->pageTextContains('Other updates were found, but they must be performed manually.');
$assert_session->fieldNotExists('projects[new_module]');
// Ensure test failures provide helpful debug output when failing readiness
// checks prevent updates.
// @see \Drupal\Tests\WebAssert::buildStatusMessageSelector()
if ($error_message = $session->getPage()->find('xpath', '//div[@data-drupal-messages]//div[@aria-label="Error message"]')) {
/** @var \Behat\Mink\Element\NodeElement $error_message */
$this->assertSame('', $error_message->getText());
}
$page->checkField('projects[alpha]');
$page->pressButton('Update');
$this->waitForBatchJob();
$assert_session->pageTextContains('Ready to update');
$page->checkField('backup');
$page->pressButton('Continue');
$this->waitForBatchJob();
$assert_session->pageTextContains('Update complete!');
$this->assertModuleVersion('alpha', '1.1.0');
$this->assertRequestedChangesWereLogged(['Update drupal/alpha from 1.0.0 to 1.1.0']);
$this->assertAppliedChangesWereLogged(['Updated drupal/alpha from 1.0.0 to 1.1.0']);
}
/**
* {@inheritdoc}
*/
public function copyCodebase(\Iterator $iterator = NULL, $working_dir = NULL): void {
parent::copyCodebase($iterator, $working_dir);
// Ensure that we will install Drupal 9.8.0 (a fake version that should
// never exist in real life) initially.
$this->setUpstreamCoreVersion('9.8.0');
}
/**
* Assert a project version is on the Available Updates page.
*
* @param string $project_title
* The project title.
* @param string $expected_version
* The expected version.
*/
protected function assertReportProjectUpdateVersion(string $project_title, string $expected_version): void {
$mink = $this->getMink();
$session = $mink->getSession();
$title_element = $session->getPage()
->find('css', ".project-update__title:contains(\"$project_title\")");
$this->assertNotNull($title_element, "Title element found for $project_title");
$version_element = $title_element->getParent()->find('css', '.project-update__version-details');
$this->assertStringContainsString($expected_version, $version_element->getText());
}
/**
* Asserts a module is a specified version.
*
* @param string $module_name
* The module name.
* @param string $version
* The expected version.
*/
private function assertModuleVersion(string $module_name, string $version): void {
$web_root = $this->getWebRoot();
$composer_json = file_get_contents("$web_root/modules/contrib/$module_name/composer.json");
$data = json_decode($composer_json, TRUE);
$this->assertSame($version, $data['version']);
}
}
<?php
declare(strict_types=1);
namespace Drupal\Tests\automatic_updates_extensions\Functional;
use Drupal\package_manager_bypass\LoggingBeginner;
use Drupal\package_manager_bypass\LoggingCommitter;
use Drupal\package_manager_bypass\NoOpStager;
use PhpTuf\ComposerStager\API\Exception\InvalidArgumentException;
use PhpTuf\ComposerStager\API\Exception\LogicException;
/**
* @covers \Drupal\automatic_updates_extensions\Form\UpdaterForm
* @group automatic_updates_extensions
* @internal
*/
class ComposerStagerOperationFailureTest extends UpdaterFormTestBase {
/**
* Tests Composer operation failure is handled properly.
*
* @param string $exception_class
* The exception class.
* @param string $service_class
* The Composer Stager service which should throw an exception.
*
* @dataProvider providerComposerOperationFailure
*/
public function testComposerOperationFailure(string $exception_class, string $service_class): void {
$page = $this->getSession()->getPage();
$assert_session = $this->assertSession();
$this->setReleaseMetadata(__DIR__ . '/../../../../package_manager/tests/fixtures/release-history/drupal.9.8.2.xml');
$this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/semver_test.1.1.xml');
$this->setProjectInstalledVersion(['semver_test' => '8.1.0']);
$this->checkForUpdates();
// Navigate to the update form.
$this->drupalGet('/admin/reports/updates');
$this->clickLink('Update Extensions');
$this->assertTableShowsUpdates(
'Semver Test',
'8.1.0',
'8.1.1',
);
$this->getStageFixtureManipulator()->setVersion('drupal/semver_test_package_name', '8.1.1');
$this->assertUpdatesCount(1);
$page->checkField('projects[semver_test]');
// Make the specified Composer Stager operation class throw an exception.
$message = $this->createComposeStagerMessage("Failure from inside $service_class");
$exception = new $exception_class($message);
call_user_func([$service_class, 'setException'], $exception);
// Start the update.
$page->pressButton('Update');
$this->checkForMetaRefresh();
// We can't continue the update after an error in the committer.
if ($service_class === LoggingCommitter::class) {
$this->acceptWarningAndUpdate();
$this->clickLink('the error page');
$assert_session->statusCodeEquals(200);
$assert_session->statusMessageContains('Automatic updates failed to apply, and the site is in an indeterminate state. Consider restoring the code and database from a backup.');
return;
}
$this->clickLink('the error page');
$assert_session->statusMessageContains($exception->getMessage());
// Make the same Composer Stager operation class NOT throw an exception.
call_user_func([$service_class, 'setException'], NULL);
// Stage should be automatically deleted when an error occurs.
$assert_session->buttonNotExists('Delete existing update');
// This ensures that we can still update after the exception no longer
// exists.
$page->checkField('projects[semver_test]');
$this->getStageFixtureManipulator()->setVersion('drupal/semver_test_package_name', '8.1.1');
$page->pressButton('Update');
$this->checkForMetaRefresh();
$this->acceptWarningAndUpdate();
$assert_session->statusMessageContains('Update complete!');
}
/**
* Data provider for testComposerOperationFailure().
*
* @return string[][]
* The test cases.
*/
public function providerComposerOperationFailure(): array {
return [
'LogicException from Beginner' => [LogicException::class, LoggingBeginner::class],
'LogicException from Stager' => [LogicException::class, NoOpStager::class],
'InvalidArgumentException from Stager' => [InvalidArgumentException::class, NoOpStager::class],
'LogicException from Committer' => [LogicException::class, LoggingCommitter::class],
];
}
}
<?php
declare(strict_types = 1);
namespace Drupal\Tests\automatic_updates_extensions\Functional;
/**
* @covers \Drupal\automatic_updates_extensions\Form\UpdaterForm
* @group automatic_updates_extensions
* @internal
*/
final class DisplayUpdatesTest extends UpdaterFormTestBase {
/**
* Data provider for testDisplayUpdates().
*
* @return array[]
* The test cases.
*/
public function providerDisplayUpdates(): array {
return [
'with unrequested updates' => [TRUE],
'without unrequested updates' => [FALSE],
];
}
/**
* Tests the form displays the correct projects which will be updated.
*
* @param bool $unrequested_updates
* Whether unrequested updates are present during update.
*
* @dataProvider providerDisplayUpdates
*/
public function testDisplayUpdates(bool $unrequested_updates): void {
$this->container->get('theme_installer')->install(['automatic_updates_theme_with_updates']);
$this->setReleaseMetadata(__DIR__ . '/../../../../package_manager/tests/fixtures/release-history/drupal.9.8.2.xml');
$this->setReleaseMetadata(__DIR__ . "/../../fixtures/release-history/semver_test.1.1.xml");
$this->setReleaseMetadata(__DIR__ . "/../../../../package_manager/tests/fixtures/release-history/aaa_update_test.1.1.xml");
$this->setProjectInstalledVersion([
'semver_test' => '8.1.0',
'aaa_update_test' => '8.x-2.0',
]);
$this->checkForUpdates();
$state = $this->container->get('state');
$page = $this->getSession()->getPage();
// Navigate to the automatic updates form.
$this->drupalGet('/admin/reports/updates');
$this->clickLink('Update Extensions');
$this->assertTableShowsUpdates(
'AAA Update test',
'8.x-2.0',
'8.x-2.1',
);
$this->assertTableShowsUpdates(
'Semver Test',
'8.1.0',
'8.1.1',
2
);
// User will choose both the projects to update and there will be no
// unrequested updates.
if ($unrequested_updates === FALSE) {
$page->checkField('projects[aaa_update_test]');
}
$page->checkField('projects[semver_test]');
$this->getStageFixtureManipulator()
->setVersion('drupal/aaa_update_test', '2.1.0')
->setVersion('drupal/semver_test_package_name', '8.1.1');
$page->pressButton('Update');
$this->checkForMetaRefresh();
$this->assertUpdateStagedTimes(1);
$assert_session = $this->assertSession();
// Both projects will be shown as requested updates if there are no
// unrequested updates, otherwise one project which user chose will be shown
// as requested update and other one will be shown as unrequested update.
if ($unrequested_updates === FALSE) {
$assert_session->pageTextNotContains('The following dependencies will also be updated:');
}
else {
$assert_session->pageTextContains('The following dependencies will also be updated:');
}
$assert_session->pageTextContains('The following projects will be updated:');
$assert_session->pageTextContains('Semver Test from 8.1.0 to 8.1.1');
$assert_session->pageTextContains('AAA Update test from 2.0.0 to 2.1.0');
}
}
<?php
declare(strict_types=1);
namespace Drupal\Tests\automatic_updates_extensions\Functional;
use Drupal\fixture_manipulator\ActiveFixtureManipulator;
/**
* @covers \Drupal\automatic_updates_extensions\Form\UpdaterForm
* @group automatic_updates_extensions
* @internal
*/
final class PreUpdateTest extends UpdaterFormTestBase {
/**
* Tests the form when modules requiring an update not installed via composer.
*/
public function testNonComposerProjects(): void {
$this->setReleaseMetadata(__DIR__ . '/../../../../package_manager/tests/fixtures/release-history/aaa_update_test.1.1.xml');
$this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/semver_test.1.1.xml');
$this->config('update.settings')
->set('fetch.url', $this->baseUrl . '/test-release-history')
->save();
$this->setProjectInstalledVersion(
[
'aaa_update_test' => '8.x-2.0',
'semver_test' => '8.1.0',
]
);
// One module not installed through composer.
(new ActiveFixtureManipulator())
->removePackage('drupal/aaa_update_test')
->commitChanges();
$assert = $this->assertSession();
$user = $this->createUser(
[
'administer site configuration',
'administer software updates',
]
);
$this->drupalLogin($user);
$this->checkForUpdates();
$this->drupalGet('admin/reports/updates/automatic-update-extensions');
$assert->pageTextContains('Other updates were found, but they must be performed manually. See the list of available updates for more information.');
$this->assertTableShowsUpdates('Semver Test', '8.1.0', '8.1.1');
$this->assertUpdatesCount(1);
// Both of the modules not installed through composer.
(new ActiveFixtureManipulator())
->removePackage('drupal/semver_test_package_name')
->commitChanges();
$this->getSession()->reload();
$assert->pageTextContains('Updates were found, but they must be performed manually. See the list of available updates for more information.');
$this->assertNoUpdates();
}
/**
* Tests the form when a module requires an update.
*/
public function testHasUpdate(): void {
$this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/semver_test.1.1.xml');
$assert = $this->assertSession();
$user = $this->createUser(['administer site configuration']);
$this->drupalLogin($user);
$this->setProjectInstalledVersion(['semver_test' => '8.1.0']);
$this->drupalGet('admin/reports/updates/automatic-update-extensions');
$assert->pageTextContains('Access Denied');
$assert->pageTextNotContains('Automatic Updates Form');
$user = $this->createUser(['administer software updates', 'administer site configuration']);
$this->drupalLogin($user);
$this->checkForUpdates();
$this->assertTableShowsUpdates('Semver Test', '8.1.0', '8.1.1');
$this->assertUpdatesCount(1);
$assert->pageTextContains('Automatic Updates Form');
$assert->buttonExists('Update');
}
/**
* Tests the form when there are no available updates.
*/
public function testNoUpdate(): void {
$this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/semver_test.1.1.xml');
$user = $this->createUser([
'administer site configuration',
'administer software updates',
]);
$this->drupalLogin($user);
$this->setProjectInstalledVersion(['semver_test' => '8.1.1']);
$this->checkForUpdates();
$this->drupalGet('admin/reports/updates/automatic-update-extensions');
$this->assertNoUpdates();
}
}
<?php
declare(strict_types = 1);
namespace Drupal\Tests\automatic_updates_extensions\Functional;
use Drupal\automatic_updates_test\EventSubscriber\TestSubscriber1;
use Drupal\package_manager\Event\StatusCheckEvent;
use Drupal\package_manager\ValidationResult;
/**
* @covers \Drupal\automatic_updates_extensions\Form\UpdaterForm
* @group automatic_updates_extensions
* @internal
*/
final class StatusCheckerRunAfterUpdateTest extends UpdaterFormTestBase {
/**
* Data provider for testStatusCheckerRunAfterUpdate().
*
* @return bool[][]
* The test cases.
*/
public function providerStatusCheckerRunAfterUpdate(): array {
return [
'has database updates' => [TRUE],
'does not have database updates' => [FALSE],
];
}
/**
* Tests status checks are run after an update.
*
* @param bool $has_database_updates
* Whether the site has database updates or not.
*
* @dataProvider providerStatusCheckerRunAfterUpdate
*/
public function testStatusCheckerRunAfterUpdate(bool $has_database_updates): void {
$this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/semver_test.1.1.xml');
$this->setProjectInstalledVersion(['semver_test' => '8.1.0']);
$this->checkForUpdates();
$page = $this->getSession()->getPage();
// Navigate to the automatic updates form.
$this->drupalGet('/admin/modules/automatic-update-extensions');
$assert_session = $this->assertSession();
$assert_session->pageTextNotContains(static::$errorsExplanation);
$assert_session->pageTextNotContains(static::$warningsExplanation);
$this->assertTableShowsUpdates('Semver Test', '8.1.0', '8.1.1');
$this->getStageFixtureManipulator()->setVersion('drupal/semver_test_package_name', '8.1.1');
$this->assertUpdatesCount(1);
$page->checkField('projects[semver_test]');
$page->pressButton('Update');
$this->checkForMetaRefresh();
$this->assertUpdateStagedTimes(1);
// Set an error before completing the update. This error should be visible
// on admin pages after completing the update without having to explicitly
// run the status checks.
TestSubscriber1::setTestResult([ValidationResult::createError([t('Error before continue.')])], StatusCheckEvent::class);
if ($has_database_updates) {
// Simulate a staged database update in the automatic_updates_test module.
// We must do this after the update has started, because the pending
// updates validator will prevent an update from starting.
$this->container->get('state')->set('automatic_updates_test.new_update', TRUE);
$this->acceptWarningAndUpdate();
$assert_session->pageTextContainsOnce('An error has occurred.');
$assert_session->pageTextContainsOnce('Continue to the error page');
$page->clickLink('the error page');
$assert_session->pageTextContains('Some modules have database schema updates to install. You should run the database update script immediately.');
$assert_session->linkExists('database update script');
$assert_session->linkByHrefExists('/update.php');
$page->clickLink('database update script');
$this->assertSession()->addressEquals('/update.php');
$assert_session->pageTextNotContains('Possible database updates have been detected in the following extension');
$page->clickLink('Continue');
// @see automatic_updates_update_1191934()
$assert_session->pageTextContains('Dynamic automatic_updates_update_1191934');
$page->clickLink('Apply pending updates');
$this->checkForMetaRefresh();
$assert_session->pageTextContains('Updates were attempted.');
}
else {
$this->acceptWarningAndUpdate();
$assert_session->addressEquals('/admin/reports/updates');
$assert_session->pageTextContainsOnce('Update complete!');
}
// Status checks should display errors on admin page.
$this->drupalGet('/admin');
// Confirm that the status checks were run and the new error is displayed.
$assert_session->statusMessageContains('Error before continue.', 'error');
$assert_session->statusMessageContains('Your site does not pass some readiness checks for automatic updates. It cannot be automatically updated until further action is performed.', 'error');
$assert_session->pageTextNotContains('Your site has not recently run an update readiness check. Rerun readiness checks now.');
}
}
<?php
declare(strict_types=1);
namespace Drupal\Tests\automatic_updates_extensions\Functional;
use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\LegacyVersionUtility;
use Drupal\package_manager_test_validation\StagedDatabaseUpdateValidator;
/**
* @covers \Drupal\automatic_updates_extensions\Form\UpdaterForm
* @group automatic_updates_extensions
* @internal
*/
final class SuccessfulUpdateTest extends UpdaterFormTestBase {
/**
* Data provider for testSuccessfulUpdate().
*
* @return mixed[][]
* The test cases.
*/
public function providerSuccessfulUpdate(): array {
return [
'maintenance mode on, semver module' => [
TRUE, 'semver_test', 'drupal/semver_test_package_name', 'Semver Test', '8.1.0', '8.1.1',
],
'maintenance mode off, legacy module' => [
FALSE, 'aaa_update_test', 'drupal/aaa_update_test', 'AAA Update test', '8.x-2.0', '8.x-2.1',
],
'maintenance mode off, legacy theme' => [
FALSE, 'automatic_updates_extensions_test_theme', 'drupal/automatic_updates_extensions_test_theme', 'Automatic Updates Extensions Test Theme', '8.x-2.0', '8.x-2.1',
],
];
}
/**
* Tests an update that has no errors or special conditions.
*
* @param bool $maintenance_mode_on
* Whether maintenance should be on at the beginning of the update.
* @param string $project_name
* The project name.
* @param string $package_name
* The package name.
* @param string $project_title
* The project title.
* @param string $installed_version
* The installed version.
* @param string $target_version
* The target version.
*
* @dataProvider providerSuccessfulUpdate
*/
public function testSuccessfulUpdate(bool $maintenance_mode_on, string $project_name, string $package_name, string $project_title, string $installed_version, string $target_version): void {
$this->container->get('theme_installer')->install(['automatic_updates_theme_with_updates']);
// By default, the Update module only checks for updates of installed
// modules and themes. The two modules we're testing here (semver_test and
// aaa_update_test) are already installed by static::$modules.
$this->container->get('theme_installer')->install(['automatic_updates_extensions_test_theme']);
$this->setReleaseMetadata(__DIR__ . '/../../../../package_manager/tests/fixtures/release-history/drupal.9.8.2.xml');
$path_to_fixtures_folder = $project_name === 'aaa_update_test' ? '/../../../../package_manager/tests' : '/../..';
$this->setReleaseMetadata(__DIR__ . $path_to_fixtures_folder . '/fixtures/release-history/' . $project_name . '.1.1.xml');
$this->setProjectInstalledVersion([$project_name => $installed_version]);
$this->getStageFixtureManipulator()->setVersion($package_name, LegacyVersionUtility::convertToSemanticVersion($target_version));
$this->checkForUpdates();
$state = $this->container->get('state');
$state->set('system.maintenance_mode', $maintenance_mode_on);
StagedDatabaseUpdateValidator::setExtensionsWithUpdates([
'system',
'automatic_updates_theme_with_updates',
]);
$page = $this->getSession()->getPage();
// Navigate to the automatic updates form.
$this->drupalGet('/admin/reports/updates');
$this->clickLink('Update Extensions');
$this->assertTableShowsUpdates(
$project_title,
$installed_version,
$target_version
);
$assert_session = $this->assertSession();
$this->assertUpdatesCount(1);
// Submit without selecting a project.
$page->pressButton('Update');
$assert_session->pageTextContains('Select one or more projects.');
// Submit with a project selected.
$page->checkField('projects[' . $project_name . ']');
$page->pressButton('Update');
$this->checkForMetaRefresh();
$this->assertUpdateStagedTimes(1);
// Confirm that the site was put into maintenance mode if needed.
$this->assertSame($state->get('system.maintenance_mode'), $maintenance_mode_on);
$assert_session->pageTextNotContains('The following dependencies will also be updated:');
// Ensure that a list of pending database updates is visible, along with a
// short explanation, in the warning messages.
$warning_messages = $assert_session->elementExists('xpath', '//div[@data-drupal-messages]//div[@aria-label="Warning message"]');
$this->assertStringContainsString('Database updates have been detected in the following extensions.<ul><li>System</li><li>Automatic Updates Theme With Updates</li></ul>', $warning_messages->getHtml());
$this->acceptWarningAndUpdate();
$assert_session->addressEquals('/admin/reports/updates');
// Confirm that the site was in maintenance before the update was applied.
// @see \Drupal\package_manager_test_validation\EventSubscriber\TestSubscriber::handleEvent()
$this->assertTrue($state->get(PreApplyEvent::class . '.system.maintenance_mode'));
$assert_session->pageTextContainsOnce('Update complete!');
// Confirm the site was returned to the original maintenance mode state.
$this->assertSame($state->get('system.maintenance_mode'), $maintenance_mode_on);
// Confirm that the apply and post-apply operations happened in
// separate requests.
// @see \Drupal\automatic_updates_test\EventSubscriber\RequestTimeRecorder
$pre_apply_time = $state->get('Drupal\package_manager\Event\PreApplyEvent time');
$post_apply_time = $state->get('Drupal\package_manager\Event\PostApplyEvent time');
$this->assertNotEmpty($pre_apply_time);
$this->assertNotEmpty($post_apply_time);
$this->assertNotSame($pre_apply_time, $post_apply_time);
}
}
<?php
declare(strict_types = 1);
namespace Drupal\Tests\automatic_updates_extensions\Functional;
use Drupal\automatic_updates_test\EventSubscriber\TestSubscriber1;
use Drupal\package_manager\Event\StatusCheckEvent;
use Drupal\package_manager\ValidationResult;
use Drupal\package_manager_test_validation\EventSubscriber\TestSubscriber;
/**
* @covers \Drupal\automatic_updates_extensions\Form\UpdaterForm
* @group automatic_updates_extensions
* @internal
*/
final class UnsuccessfulUpdateTest extends UpdaterFormTestBase {
/**
* Test the form for warning messages.
*/
public function testWarnings(): void {
$this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/semver_test.1.1.xml');
$assert = $this->assertSession();
$this->setProjectInstalledVersion(['semver_test' => '8.1.0']);
$this->checkForUpdates();
$message = t("Warning! Updating this module may cause an error.");
$warning = ValidationResult::createWarning([$message]);
TestSubscriber1::setTestResult([$warning], StatusCheckEvent::class);
// Navigate to the automatic updates form.
$this->drupalGet('/admin/reports/updates');
$this->clickLink('Update Extensions');
$this->assertTableShowsUpdates('Semver Test', '8.1.0', '8.1.1');
$this->getStageFixtureManipulator()->setVersion('drupal/semver_test_package_name', '8.1.1');
$this->assertUpdatesCount(1);
$this->checkForMetaRefresh();
$assert->pageTextNotContains(static::$errorsExplanation);
$assert->elementExists('css', '#edit-projects-semver-test')->check();
$assert->checkboxChecked('edit-projects-semver-test');
// No explanation is given for warnings.
$assert->pageTextNotContains(static::$warningsExplanation);
$assert->buttonExists('Update');
// Add warnings from StatusCheckEvent.
$summary_status_check_event = t('Some summary');
$messages_status_check_event = [
t("The only thing we're allowed to do is to"),
t("believe that we won't regret the choice"),
t("we made."),
];
$warning_status_check_event = ValidationResult::createWarning($messages_status_check_event, $summary_status_check_event);
TestSubscriber::setTestResult([$warning_status_check_event], StatusCheckEvent::class);
$this->getSession()->getPage()->pressButton('Update');
$this->checkForMetaRefresh();
$assert->buttonExists('Continue');
$assert->pageTextContains((string) $summary_status_check_event);
foreach ($messages_status_check_event as $message) {
$assert->pageTextContains((string) $message);
}
}
/**
* Tests the form when an uninstallable module requires an update.
*/
public function testUninstallableRelease(): void {
$this->container->get('state')->set('testUninstallableRelease', TRUE);
$this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/semver_test.1.1.xml');
$this->setProjectInstalledVersion(['semver_test' => '8.1.0']);
$user = $this->createUser(['administer software updates', 'administer site configuration']);
$this->drupalLogin($user);
$this->drupalGet('admin/reports/updates/automatic-update-extensions');
$this->checkForUpdates();
$this->assertNoUpdates();
}
}
<?php
declare(strict_types = 1);
namespace Drupal\Tests\automatic_updates_extensions\Functional;
use Drupal\automatic_updates_test\EventSubscriber\TestSubscriber1;
use Drupal\package_manager\Event\StatusCheckEvent;
use Drupal\package_manager\ValidationResult;
use Drupal\package_manager_bypass\LoggingCommitter;
use Drupal\package_manager_test_validation\EventSubscriber\TestSubscriber;
/**
* @covers \Drupal\automatic_updates_extensions\Form\UpdaterForm
* @group automatic_updates_extensions
* @internal
*/
final class UpdateErrorTest extends UpdaterFormTestBase {
/**
* Tests that an exception is thrown if a previous apply failed.
*/
public function testMarkerFileFailure(): void {
$this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/semver_test.1.1.xml');
$this->setProjectInstalledVersion(['semver_test' => '8.1.0']);
$this->checkForUpdates();
$page = $this->getSession()->getPage();
// Navigate to the automatic updates form.
$this->drupalGet('/admin/modules/automatic-update-extensions');
$assert_session = $this->assertSession();
$assert_session->pageTextNotContains(static::$errorsExplanation);
$assert_session->pageTextNotContains(static::$warningsExplanation);
$this->assertTableShowsUpdates('Semver Test', '8.1.0', '8.1.1');
$this->getStageFixtureManipulator()->setVersion('drupal/semver_test_package_name', '8.1.1');
$this->assertUpdatesCount(1);
$page->checkField('projects[semver_test]');
$page->pressButton('Update');
$this->checkForMetaRefresh();
$this->assertUpdateStagedTimes(1);
$assert_session->pageTextNotContains('The following dependencies will also be updated:');
LoggingCommitter::setException(new \Exception('failed at committer'));
$this->acceptWarningAndUpdate();
$failure_message = 'Automatic updates failed to apply, and the site is in an indeterminate state. Consider restoring the code and database from a backup.';
$assert_session->pageTextContainsOnce('An error has occurred.');
$assert_session->pageTextContains($failure_message);
$page->clickLink('the error page');
// We should be on the form (i.e., 200 response code), but unable to
// continue the update.
$assert_session->statusCodeEquals(200);
$assert_session->pageTextContains($failure_message);
$assert_session->buttonNotExists('Continue');
// The same thing should be true if we try to start from the beginning.
$this->drupalGet('/admin/modules/automatic-update-extensions');
$assert_session->statusCodeEquals(200);
$assert_session->pageTextContains($failure_message);
$assert_session->buttonNotExists('Update');
}
/**
* Test the form for errors.
*/
public function testErrors(): void {
$this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/semver_test.1.1.xml');
$assert = $this->assertSession();
$user = $this->createUser([
'administer site configuration',
'administer software updates',
]);
$this->drupalLogin($user);
$this->setProjectInstalledVersion(['semver_test' => '8.1.0']);
$this->checkForUpdates();
$this->drupalGet('admin/reports/updates/automatic-update-extensions');
$this->assertTableShowsUpdates('Semver Test', '8.1.0', '8.1.1');
$this->assertUpdatesCount(1);
$message = t("You've not experienced Shakespeare until you have read him in the original Klingon.");
$error = ValidationResult::createError([$message]);
TestSubscriber1::setTestResult([$error], StatusCheckEvent::class);
$this->getSession()->reload();
$assert->pageTextContains((string) $message);
$assert->pageTextContains(static::$errorsExplanation);
$assert->pageTextNotContains(static::$warningsExplanation);
$assert->buttonNotExists('Update');
}
/**
* Tests that messages from StatusCheckEvent are shown on the confirmation form.
*/
public function testStatusErrorMessages(): void {
$this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/semver_test.1.1.xml');
$assert = $this->assertSession();
$this->setProjectInstalledVersion(['semver_test' => '8.1.0']);
$this->checkForUpdates();
$this->drupalGet('admin/reports/updates/automatic-update-extensions');
$this->assertTableShowsUpdates('Semver Test', '8.1.0', '8.1.1');
$this->assertUpdatesCount(1);
$this->getSession()->reload();
$assert->elementExists('css', '#edit-projects-semver-test')->check();
$assert->checkboxChecked('edit-projects-semver-test');
$assert->buttonExists('Update');
$messages = [
t("The only thing we're allowed to do is to"),
t("believe that we won't regret the choice"),
t("we made."),
];
$summary = t('Some summary');
$error = ValidationResult::createError($messages, $summary);
TestSubscriber::setTestResult([$error], StatusCheckEvent::class);
$this->getSession()->getPage()->pressButton('Update');
$this->checkForMetaRefresh();
$assert->pageTextContains(static::$errorsExplanation);
$assert->pageTextNotContains(static::$warningsExplanation);
$assert->pageTextContains((string) $summary);
foreach ($messages as $message) {
$assert->pageTextContains((string) $message);
}
$assert->buttonNotExists('Continue');
}
}
<?php
declare(strict_types = 1);
namespace Drupal\Tests\automatic_updates_extensions\Functional;
use Drupal\fixture_manipulator\ActiveFixtureManipulator;
use Drupal\package_manager\PathLocator;
use Drupal\Tests\automatic_updates_extensions\Traits\FormTestTrait;
use Drupal\Tests\automatic_updates\Functional\UpdaterFormTestBase as UpdaterFormFunctionalTestBase;
/**
* Base class for functional tests of updater form.
*
* @internal
* This class is an internal part of the module's testing infrastructure and
* should not be used by external code.
*/
abstract class UpdaterFormTestBase extends UpdaterFormFunctionalTestBase {
use FormTestTrait;
/**
* {@inheritdoc}
*/
protected static $errorsExplanation = 'Your site cannot be automatically updated until further action is performed.';
/**
* The path of the test project's active directory.
*
* @var string
*/
private $activeDir;
/**
* {@inheritdoc}
*/
protected static $modules = [
'automatic_updates_extensions',
'semver_test',
'aaa_update_test',
'automatic_updates_extensions_test',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->activeDir = $this->container->get(PathLocator::class)->getProjectRoot();
(new ActiveFixtureManipulator())
// Add a package where the Composer package name,
// drupal/semver_test_package_name, does not match the project name,
// semver_test.
->addPackage(
[
'name' => 'drupal/semver_test_package_name',
'version' => '8.1.0',
'type' => 'drupal-module',
],
extra_files: [
'semver_test.info.yml' => '{name: "Semver Test", project: "semver_test", type: "module"}',
]
)
->addPackage([
'name' => 'drupal/aaa_update_test',
'version' => '2.0.0',
'type' => 'drupal-module',
])
->addPackage([
'name' => 'drupal/automatic_updates_extensions_test_theme',
'version' => '2.0.0',
'type' => 'drupal-theme',
])
->commitChanges();
$this->drupalPlaceBlock('local_tasks_block', ['primary' => TRUE]);
}
/**
* Sets installed project version.
*
* @todo Remove this function with use of the trait from the Update module in
* https://drupal.org/i/3348234.
*/
protected function setProjectInstalledVersion($project_versions): void {
$this->config('update.settings')
->set('fetch.url', $this->baseUrl . '/test-release-history')
->save();
$system_info = [];
foreach ($project_versions as $project_name => $version) {
$system_info[$project_name] = [
'project' => $project_name,
'version' => $version,
'hidden' => FALSE,
];
}
$system_info['drupal'] = [
'project' => 'drupal',
'version' => '8.0.0',
'hidden' => FALSE,
];
$this->config('update_test.settings')
->set('system_info', $system_info)
->save();
}
/**
* Asserts the table shows the updates.
*
* @param string $expected_project_title
* The expected project title.
* @param string $expected_installed_version
* The expected installed version.
* @param string $expected_target_version
* The expected target version.
* @param int $row
* The row number.
*/
protected function assertTableShowsUpdates(string $expected_project_title, string $expected_installed_version, string $expected_target_version, int $row = 1): void {
$this->assertUpdateTableRow($this->assertSession(), $expected_project_title, $expected_installed_version, $expected_target_version, $row);
}
/**
* Asserts the form shows no updates.
*/
protected function assertNoUpdates(): void {
$assert = $this->assertSession();
$assert->buttonNotExists('Update');
$assert->pageTextContains('There are no available updates.');
}
/**
* {@inheritdoc}
*/
protected function checkForUpdates(): void {
$this->drupalGet('/admin/modules/automatic-update-extensions');
$this->clickLink('Check manually');
$this->checkForMetaRefresh();
}
/**
* Continue the update after checking the backup warning checkbox.
*/
protected function acceptWarningAndUpdate(): void {
$page = $this->getSession()->getPage();
$page->pressButton('Continue');
$this->assertSession()->statusMessageContains('Warning: Updating contributed modules or themes may leave your site inoperable or looking wrong. field is required.', 'error');
$page->checkField('backup');
$page->pressButton('Continue');
$this->checkForMetaRefresh();
}
}
<?php
declare(strict_types = 1);
namespace Drupal\Tests\automatic_updates_extensions\Kernel;
use Drupal\automatic_updates_extensions\ExtensionUpdateStage;
use Drupal\fixture_manipulator\ActiveFixtureManipulator;
use Drupal\package_manager\Event\PreOperationStageEvent;
use Drupal\package_manager\Exception\StageEventException;
use Drupal\package_manager\Validator\ComposerValidator;
use Drupal\Tests\automatic_updates\Kernel\AutomaticUpdatesKernelTestBase;
/**
* Base class for kernel tests of the Automatic Updates Extensions module.
*
* @internal
* This class is an internal part of the module's testing infrastructure and
* should not be used by external code.
*/
abstract class AutomaticUpdatesExtensionsKernelTestBase extends AutomaticUpdatesKernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'automatic_updates_extensions',
'package_manager_test_release_history',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
// Disable the Composer executable validator, since it may cause the tests
// to fail if a supported version of Composer is unavailable to the web
// server. This should be okay in most situations because, apart from the
// validator, only Composer Stager needs run Composer, and
// package_manager_bypass is disabling those operations.
$this->disableValidators[] = ComposerValidator::class;
parent::setUp();
// Install additional packages that will be needed in tests.
(new ActiveFixtureManipulator())
->addPackage([
"name" => "drupal/my_module",
"version" => "9.8.0",
"type" => "drupal-module",
])
->addPackage([
"name" => "drupal/contrib_profile1",
"version" => "1.0.0",
"type" => "drupal-profile",
])
->addPackage([
"name" => "drupal/my_dev_module",
"version" => "9.8.1",
"type" => "drupal-module",
], TRUE)
->addPackage([
"name" => "drupal/semver_test",
"version" => "8.1.0",
"type" => "drupal-module",
])
->addPackage([
"name" => "drupal/aaa_update_test",
"version" => "1.0.0",
"type" => "drupal-module",
])
->addPackage([
"name" => "drupal/package_manager_test_update",
"version" => "1.0.0",
"type" => "drupal-module",
])->commitChanges();
}
/**
* Asserts validation results are returned from a stage life cycle event.
*
* @param string[] $project_versions
* The project versions.
* @param \Drupal\package_manager\ValidationResult[] $expected_results
* The expected validation results.
* @param string|null $event_class
* (optional) The class of the event which should return the results. Must
* be passed if $expected_results is not empty.
*/
protected function assertUpdateResults(array $project_versions, array $expected_results, string $event_class = NULL): void {
$stage = $this->container->get(ExtensionUpdateStage::class);
try {
$stage->begin($project_versions);
$stage->stage();
$stage->apply();
$stage->postApply();
$stage->destroy();
// If we did not get an exception, ensure we didn't expect any results.
$this->assertEmpty($expected_results);
}
catch (StageEventException $e) {
$this->assertNotEmpty($expected_results);
$exception_event = $e->event;
$this->assertInstanceOf($event_class, $exception_event);
$this->assertInstanceOf(PreOperationStageEvent::class, $exception_event);
$this->assertValidationResultsEqual($expected_results, $e->event->getResults());
}
}
}
<?php
declare(strict_types = 1);
namespace Drupal\Tests\automatic_updates_extensions\Kernel;
use Drupal\automatic_updates_extensions\ExtensionUpdateStage;
use Drupal\automatic_updates_extensions\Validator\UpdateReleaseValidator;
use Drupal\Tests\user\Traits\UserCreationTrait;
use PhpTuf\ComposerStager\API\Core\StagerInterface;
/**
* @coversDefaultClass \Drupal\automatic_updates_extensions\ExtensionUpdateStage
* @group automatic_updates_extensions
* @internal
*/
final class ExtensionUpdateStageTest extends AutomaticUpdatesExtensionsKernelTestBase {
use UserCreationTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'automatic_updates',
'automatic_updates_test',
'automatic_updates_extensions',
'user',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
// This test doesn't need to validate that the test projects used are in the
// codebase. Therefore, we need to disable the following validators that
// require real Drupal projects.
$this->disableValidators[] = UpdateReleaseValidator::class;
parent::setUp();
$this->installEntitySchema('user');
// Create a user who will own the stage even after the container is rebuilt.
$user = $this->createUser([], NULL, TRUE, ['uid' => 2]);
$this->setCurrentUser($user);
}
/**
* Tests that correct versions are staged after calling ::begin().
*/
public function testCorrectVersionsStaged(): void {
$id = $this->container->get(ExtensionUpdateStage::class)->begin([
'my_module' => '9.8.1',
// Use a legacy version number to ensure they are converted to semantic
// version numbers which will work with the drupal.org Composer facade.
'my_dev_module' => '8.x-1.2-alpha1@alpha',
]);
$user = $this->container->get('current_user')->getAccount();
// Rebuild the container to ensure the package versions are persisted.
/** @var \Drupal\Core\DrupalKernel $kernel */
$kernel = $this->container->get('kernel');
$kernel->rebuildContainer();
$this->container = $kernel->getContainer();
// Keep using the user account we created.
$this->setCurrentUser($user);
$stage = $this->container->get(ExtensionUpdateStage::class);
// Ensure that the target package versions are what we expect.
$expected_versions = [
'production' => [
'drupal/my_module' => '9.8.1',
],
'dev' => [
'drupal/my_dev_module' => '1.2.0-alpha1@alpha',
],
];
$this->assertSame($expected_versions, $stage->claim($id)->getPackageVersions());
// When we call ExtensionUpdateStage::stage(), the stored project versions
// should be read from state and passed to Composer Stager's Stager service,
// in the form of a Composer command. This is done using
// package_manager_bypass's invocation recorder, rather than a regular mock,
// in order to test that the invocation recorder itself works. The
// production requirements are changed first, followed by the dev
// requirements. Then the installed packages are updated. This is tested
// functionally in Package Manager.
// @see \Drupal\Tests\package_manager\Build\StagedUpdateTest
$expected_arguments = [
[
'require',
'--no-update',
'drupal/my_module:9.8.1',
],
[
'require',
'--dev',
'--no-update',
'drupal/my_dev_module:1.2.0-alpha1@alpha',
],
[
'update',
'--with-all-dependencies',
'--optimize-autoloader',
'drupal/my_module:9.8.1',
'drupal/my_dev_module:1.2.0-alpha1@alpha',
],
];
$stage->stage();
$actual_arguments = $this->container->get(StagerInterface::class)
->getInvocationArguments();
$this->assertCount(count($expected_arguments), $actual_arguments);
foreach ($actual_arguments as $i => [$arguments]) {
$this->assertSame($expected_arguments[$i], $arguments);
}
}
/**
* Tests that attempting to update an install profile throws an exception.
*/
public function testUpdatingInstallProfile(): void {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage("The project contrib_profile1 cannot be updated because updating install profiles is not supported.");
$this->container->get(ExtensionUpdateStage::class)
->begin([
'contrib_profile1' => '1.1.0',
]);
}
/**
* Tests that an exception is thrown when calling begin() with no projects.
*/
public function testNoProjectsInBegin(): void {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('No projects to begin the update');
$this->container->get(ExtensionUpdateStage::class)->begin([]);
}
/**
* Tests exception if a Drupal project unknown to composer sent to ::begin().
*/
public function testUnknownDrupalProject(): void {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage("The project my_module_unknown is not a Drupal project known to Composer and cannot be updated.");
$this->container->get(ExtensionUpdateStage::class)->begin([
'my_module_unknown' => '9.8.1',
]);
}
}
<?php
namespace Drupal\Tests\automatic_updates_extensions\Kernel\Validator;
use Drupal\automatic_updates_extensions\ExtensionUpdateStage;
use Drupal\package_manager\Exception\StageEventException;
use Drupal\package_manager\ValidationResult;
use Drupal\Tests\automatic_updates_extensions\Kernel\AutomaticUpdatesExtensionsKernelTestBase;
/**
* @coversDefaultClass \Drupal\automatic_updates_extensions\Validator\ForbidCoreChangesValidator
* @group automatic_updates_extensions
* @internal
*/
class ForbidCoreChangesValidatorTest extends AutomaticUpdatesExtensionsKernelTestBase {
/**
* Tests error messages if requested updates were not staged.
*
* @param array $staged_versions
* An array of the staged versions where the keys are the package names and
* the values are the package versions or NULL if the package should be
* removed in the stage.
* @param string[][] $new_packages
* An array of the new packages to add to the stage.
* @param \Drupal\package_manager\ValidationResult[] $expected_results
* The expected validation results.
*
* @dataProvider providerTestErrorMessage
*/
public function testErrorMessages(array $staged_versions, array $new_packages, array $expected_results): void {
$this->setReleaseMetadata([
'semver_test' => __DIR__ . '/../../../fixtures/release-history/semver_test.1.1.xml',
'drupal' => __DIR__ . '/../../../../../package_manager/tests/fixtures/release-history/drupal.9.8.2.xml',
]);
$this->getStageFixtureManipulator()->addPackage([
'name' => 'drupal/non-core',
'version' => '1.0.0',
'type' => 'package',
]);
foreach ($staged_versions as $package => $version) {
if ($version === NULL) {
$this->getStageFixtureManipulator()->removePackage($package);
continue;
}
$this->getStageFixtureManipulator()->setVersion($package, $version);
}
foreach ($new_packages as $package) {
$this->getStageFixtureManipulator()->addPackage($package);
}
$this->getStageFixtureManipulator()->setVersion('drupal/semver_test', '8.1.1');
$stage = $this->container->get(ExtensionUpdateStage::class);
$stage->begin([
'semver_test' => '8.1.1',
]);
$stage->stage();
$this->assertStatusCheckResults($expected_results, $stage);
try {
$stage->apply();
$this->fail('Expecting an exception.');
}
catch (StageEventException $exception) {
$this->assertExpectedResultsFromException($expected_results, $exception);
}
}
/**
* Data provider for testErrorMessage().
*
* @return mixed[]
* The test cases.
*/
public function providerTestErrorMessage(): array {
$summary = t('Updating Drupal Core while updating extensions is currently not supported. Use <a href="/admin/reports/updates/update">this form</a> to update Drupal core. The following changes were made to the Drupal core packages:');
return [
'drupal/core updated, non-core updated' => [
[
'drupal/core' => '9.8.1',
'drupal/non-core' => '1.0.1',
],
[],
[ValidationResult::createError([t("'drupal/core' version changed from 9.8.0 to 9.8.1.")], $summary)],
],
'drupal/core-recommended and drupal/core updated, non-core package installed' => [
[
'drupal/core-recommended' => '9.8.1',
'drupal/core' => '9.8.1',
],
[
[
'name' => 'other-org/other-package',
'type' => 'package',
],
],
[
ValidationResult::createError(
[
t("'drupal/core-recommended' version changed from 9.8.0 to 9.8.1."),
t("'drupal/core' version changed from 9.8.0 to 9.8.1."),
],
$summary
),
],
],
'drupal/core-recommended removed, drupal/core updated, drupal/core-composer-scaffold installed, non-core package removed' => [
[
'drupal/core-recommended' => NULL,
'drupal/core' => '9.8.1',
'drupal/non-core' => NULL,
],
[
[
'name' => 'drupal/core-composer-scaffold',
'type' => 'package',
],
],
[
ValidationResult::createError(
[
t("'drupal/core-composer-scaffold' installed."),
t("'drupal/core-recommended' removed."),
t("'drupal/core' version changed from 9.8.0 to 9.8.1."),
],
$summary
),
],
],
];
}
}
<?php
declare(strict_types=1);
namespace Drupal\Tests\automatic_updates_extensions\Kernel\Validator;
use Drupal\automatic_updates_extensions\ExtensionUpdateStage;
use Drupal\fixture_manipulator\ActiveFixtureManipulator;
use Drupal\package_manager\Exception\StageEventException;
use Drupal\package_manager\ValidationResult;
use Drupal\Tests\automatic_updates_extensions\Kernel\AutomaticUpdatesExtensionsKernelTestBase;
/**
* @coversDefaultClass \Drupal\automatic_updates_extensions\Validator\RequestedUpdateValidator
* @group automatic_updates_extensions
* @internal
*/
class RequestedUpdateValidatorTest extends AutomaticUpdatesExtensionsKernelTestBase {
/**
* Tests error messages if requested updates were not staged.
*
* @param array $staged_versions
* An array of the staged versions where the keys are the package names and
* the values are the package versions.
* @param array $expected_results
* The expected validation results.
*
* @dataProvider providerTestErrorMessage
*/
public function testErrorMessage(array $staged_versions, array $expected_results): void {
if ($staged_versions) {
// If we are going to stage updates to Drupal packages also update a
// non-Drupal. The validator should ignore the non-Drupal packages.
(new ActiveFixtureManipulator())
->addPackage([
"name" => 'vendor/non-drupal-package',
"version" => "1.0.0",
"type" => "drupal-module",
])
->commitChanges();
$this->getStageFixtureManipulator()->setVersion('vendor/non-drupal-package', '1.0.1');
foreach ($staged_versions as $package => $version) {
$this->getStageFixtureManipulator()->setVersion($package, $version);
}
}
$this->setReleaseMetadata([
'semver_test' => __DIR__ . '/../../../fixtures/release-history/semver_test.1.1.xml',
'drupal' => __DIR__ . '/../../../../../package_manager/tests/fixtures/release-history/drupal.9.8.2.xml',
'aaa_update_test' => __DIR__ . "/../../../../../package_manager/tests/fixtures/release-history/aaa_update_test.1.1.xml",
]);
// Set the project version to '8.0.1' so that there 2 versions of above this
// that will be in the list of supported releases, 8.1.0 and 8.1.1.
(new ActiveFixtureManipulator())
->setVersion('drupal/semver_test', '8.0.1')
->commitChanges();
// @todo Replace with use of the trait from the Update module in https://drupal.org/i/3348234.
$module_info = ['version' => '8.0.1', 'project' => 'semver_test'];
$this->config('update_test.settings')
->set("system_info.semver_test", $module_info)
->save();
$stage = $this->container->get(ExtensionUpdateStage::class);
$stage->begin([
'semver_test' => '8.1.1',
'aaa_update_test' => '8.x-1.1',
]);
$stage->stage();
$this->assertStatusCheckResults($expected_results, $stage);
try {
$stage->apply();
$this->fail('Expecting an exception.');
}
catch (StageEventException $exception) {
$this->assertExpectedResultsFromException($expected_results, $exception);
}
}
/**
* Data provider for testErrorMessage().
*
* @return mixed[]
* The test cases.
*/
public function providerTestErrorMessage() {
return [
'no updates' => [
[],
[
ValidationResult::createError([t('No updates detected in the staging area.')]),
],
],
'1 project not updated' => [
[
'drupal/aaa_update_test' => '1.1.0',
],
[
ValidationResult::createError([t("The requested update to 'drupal/semver_test' to version '8.1.1' was not performed.")]),
],
],
'project updated to wrong version' => [
[
'drupal/semver_test' => '8.1.0',
'drupal/aaa_update_test' => '1.1.0',
],
[
ValidationResult::createError([t("The requested update to 'drupal/semver_test' to version '8.1.1' does not match the actual staged update to '8.1.0'.")]),
],
],
];
}
}
<?php
declare(strict_types = 1);
namespace Drupal\Tests\automatic_updates_extensions\Kernel\Validator;
use Drupal\package_manager\LegacyVersionUtility;
use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\ValidationResult;
use Drupal\Tests\automatic_updates_extensions\Kernel\AutomaticUpdatesExtensionsKernelTestBase;
/**
* @coversDefaultClass \Drupal\automatic_updates_extensions\Validator\UpdateReleaseValidator
* @group automatic_updates_extensions
* @internal
*/
final class UpdateReleaseValidatorTest extends AutomaticUpdatesExtensionsKernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['automatic_updates'];
/**
* Data provider for testPreCreateException().
*
* @return mixed[][]
* The test cases.
*/
public function providerTestPreCreateException(): array {
return [
'semver, supported update' => ['semver_test', '8.1.0', '8.1.1', FALSE],
'semver, update to unsupported branch' => ['semver_test', '8.1.0', '8.2.0', TRUE],
'legacy, supported update' => ['aaa_update_test', '8.x-2.0', '8.x-2.1', FALSE],
'legacy, update to unsupported branch' => ['aaa_update_test', '8.x-2.0', '8.x-3.0', TRUE],
];
}
/**
* Tests updating to a release during pre-create.
*
* @param string $project
* The project to update.
* @param string $installed_version
* The installed version of the project.
* @param string $target_version
* The target version.
* @param bool $error_expected
* Whether an error is expected in the update.
*
* @dataProvider providerTestPreCreateException
*/
public function testPreCreateException(string $project, string $installed_version, string $target_version, bool $error_expected): void {
$this->enableModules([$project]);
// @todo Replace with use of the trait from the Update module in https://drupal.org/i/3348234.
$module_info = ['version' => $installed_version, 'project' => $project];
$this->config('update_test.settings')
->set("system_info.$project", $module_info)
->save();
$path_to_fixtures_folder = $project === 'aaa_update_test' ? '/../../../../../package_manager/tests/' : '/../../../';
$this->setReleaseMetadata([
$project => __DIR__ . $path_to_fixtures_folder . "fixtures/release-history/$project.1.1.xml",
'drupal' => __DIR__ . '/../../../../../package_manager/tests/fixtures/release-history/drupal.9.8.2.xml',
]);
if ($error_expected) {
$expected_results = [
ValidationResult::createError(
[
t('Project @project to version @target_version', [
'@project' => $project,
'@target_version' => LegacyVersionUtility::convertToSemanticVersion($target_version),
]),
],
t('Cannot update because the following project version is not in the list of installable releases.')
),
];
}
else {
// Ensure the correct version of the package is staged because the update
// is expected to succeed.
$this->getStageFixtureManipulator()->setVersion("drupal/$project", LegacyVersionUtility::convertToSemanticVersion($target_version));
$expected_results = [];
}
$this->assertUpdateResults([$project => $target_version], $expected_results, PreCreateEvent::class);
}
}
<?php
declare(strict_types=1);
namespace Drupal\Tests\automatic_updates_extensions\Traits;
use Behat\Mink\WebAssert;
use Drupal\Tests\BrowserTestBase;
/**
* Common methods for testing the update form.
*
* @internal
* This class is an internal part of the module's testing infrastructure and
* should not be used by external code.
*/
trait FormTestTrait {
/**
* Asserts the table shows the updates.
*
* @param \Behat\Mink\WebAssert $assert
* The web assert tool.
* @param string $expected_project_title
* The expected project title.
* @param string $expected_installed_version
* The expected installed version.
* @param string $expected_target_version
* The expected target version.
* @param int $row
* The row number.
*/
private function assertUpdateTableRow(WebAssert $assert, string $expected_project_title, string $expected_installed_version, string $expected_target_version, int $row = 1): void {
$row_selector = ".update-recommended tr:nth-of-type($row)";
$assert->elementTextContains('css', $row_selector . ' td:nth-of-type(2)', $expected_project_title);
$assert->elementTextContains('css', $row_selector . ' td:nth-of-type(3)', $expected_installed_version);
$target_selector = $row_selector . ' td:nth-of-type(4)';
$cell = $assert->elementExists('css', $target_selector);
$link_url = $assert->elementExists('named', ['link', 'Release notes'], $cell)->getAttribute('href');
$this->assertStringContainsString(str_replace('.', '-', $expected_target_version) . '-release', $link_url);
}
/**
* Asserts the table shows the expected number of updates.
*
* @param int $expected_update_count
* The no of rows in table.
*/
protected function assertUpdatesCount(int $expected_update_count): void {
assert($this instanceof BrowserTestBase);
$this->assertSession()->elementsCount('css', '.update-recommended tbody tr', $expected_update_count);
}
}
name: Test theme
type: theme
package: Testing
description: 'A test theme.'
core_version_requirement: ^8 || ^9
base theme: false
regions:
header: 'Header'
content: 'Content'
sidebar_first: 'Sidebar first'
footer: 'Footer'
{
"name": "drupal/automatic_updates",
"type": "drupal-module",
"description": "Drupal Automatic Updates",
"keywords": ["Drupal"],
"license": "GPL-2.0-or-later",
"homepage": "https://www.drupal.org/project/automatic_updates",
"minimum-stability": "dev",
"support": {
"issues": "https://www.drupal.org/project/issues/automatic_updates",
"source": "http://cgit.drupalcode.org/automatic_updates"
},
"require": {
"ext-json": "*",
"php-tuf/composer-stager": "0.2.1"
},
"config": {
"platform": {
"php": "7.3.0"
}
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/php-tuf/composer-stager"
}
]
"name": "drupal/automatic_updates",
"type": "drupal-module",
"description": "Drupal Automatic Updates",
"keywords": [
"Drupal"
],
"license": "GPL-2.0-or-later",
"homepage": "https://www.drupal.org/project/automatic_updates",
"minimum-stability": "dev",
"support": {
"issues": "https://www.drupal.org/project/issues/automatic_updates",
"source": "http://cgit.drupalcode.org/automatic_updates"
},
"require": {
"ext-json": "*",
"php-tuf/composer-stager": "2.0-beta3",
"composer-runtime-api": "^2.1",
"symfony/console": "^6.2"
},
"require-dev": {
"colinodell/psr-testlogger": "^1.2",
"symfony/config": "^6.2"
},
"scripts": {
"phpcbf": "scripts/phpcbf.sh",
"phpcs": "scripts/phpcs.sh",
"test": [
"Composer\\Config::disableProcessTimeout",
"scripts/phpunit.sh"
],
"core-convert": "Drupal\\automatic_updates\\Development\\ConverterCommand",
"core-commit": "Drupal\\automatic_updates\\Development\\ConverterCommand::makeCommit"
},
"scripts-descriptions": {
"phpcbf": "Automatically fixes standards violations where possible.",
"phpcs": "Checks code for standards compliance.",
"test": "Runs PHPUnit tests.",
"core-convert": "Converts this module to a core merge request. For arguments and options see \\Drupal\\automatic_updates\\Development\\ConverterCommand::configure().",
"core-commit": "Converts this module to a core merge request. Excepts 1 arguments. The core clone directory."
},
"autoload": {
"psr-4": {
"Drupal\\automatic_updates\\Development\\": "scripts/src"
}
},
"bin": ["auto-update"]
}
unattended:
method: web
level: disable
allow_core_minor_updates: false
status_check_mail: errors_only
This diff is collapsed.
/**
* @file
* Styles used by the Automatic Updates module.
*/
.automatic-updates-unsupported-version .project-update__download-link {
display: none;
}