Skip to content
Snippets Groups Projects

Compare revisions

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

Source

Select target project
No results found

Target

Select target project
  • project/automatic_updates
  • issue/automatic_updates-3159719
  • issue/automatic_updates-3227923
  • issue/automatic_updates-3227927
  • issue/automatic_updates-3227122
  • issue/automatic_updates-3227940
  • issue/automatic_updates-3228095
  • issue/automatic_updates-3228101
  • issue/automatic_updates-3228115
  • issue/automatic_updates-3228125
  • issue/automatic_updates-3228359
  • issue/automatic_updates-3228392
  • issue/automatic_updates-3225753
  • issue/automatic_updates-3227588
  • issue/automatic_updates-3228521
  • issue/automatic_updates-3228539
  • issue/automatic_updates-3226570
  • issue/automatic_updates-3228806
  • issue/automatic_updates-3227575
  • issue/automatic_updates-3229485
  • issue/automatic_updates-3228955
  • issue/automatic_updates-3230024
  • issue/automatic_updates-3230250
  • issue/automatic_updates-3230249
  • issue/automatic_updates-3230264
  • issue/automatic_updates-3230510
  • issue/automatic_updates-3230235
  • issue/automatic_updates-3230050
  • issue/automatic_updates-3230934
  • issue/automatic_updates-3230049
  • issue/automatic_updates-3230507
  • issue/automatic_updates-3231153
  • issue/automatic_updates-3231992
  • issue/automatic_updates-3232003
  • issue/automatic_updates-3232004
  • issue/automatic_updates-3231996
  • issue/automatic_updates-3231999
  • issue/automatic_updates-3230668
  • issue/automatic_updates-3232000
  • issue/automatic_updates-3232420
  • issue/automatic_updates-3232729
  • issue/automatic_updates-3232761
  • issue/automatic_updates-3231997
  • issue/automatic_updates-3232927
  • issue/automatic_updates-3232959
  • issue/automatic_updates-3233124
  • issue/automatic_updates-3230856
  • issue/automatic_updates-3233493
  • issue/automatic_updates-3233587
  • issue/automatic_updates-3233521
  • issue/automatic_updates-3236405
  • issue/automatic_updates-3236299
  • issue/automatic_updates-3238586
  • issue/automatic_updates-3238647
  • issue/automatic_updates-3238717
  • issue/automatic_updates-3238846
  • issue/automatic_updates-3238852
  • issue/automatic_updates-3238866
  • issue/automatic_updates-3238714
  • issue/automatic_updates-3239103
  • issue/automatic_updates-3233138
  • issue/automatic_updates-3239466
  • issue/automatic_updates-3239645
  • issue/automatic_updates-3239673
  • issue/automatic_updates-3277775
  • issue/automatic_updates-3280923
  • issue/automatic_updates-3275315
  • issue/automatic_updates-3279527
  • issue/automatic_updates-3279733
  • issue/automatic_updates-3281405
  • issue/automatic_updates-3281397
  • issue/automatic_updates-3280204
  • issue/automatic_updates-3277817
  • issue/automatic_updates-3277230
  • issue/automatic_updates-3276534
  • issue/automatic_updates-3279538
  • issue/automatic_updates-3280168
  • issue/automatic_updates-3271502
  • issue/automatic_updates-3283644
  • issue/automatic_updates-3302524
  • issue/automatic_updates-3275883
  • issue/automatic_updates-3280180
  • issue/automatic_updates-3274837
  • issue/automatic_updates-3281473
  • issue/automatic_updates-3281634
  • issue/automatic_updates-3239889
  • issue/automatic_updates-3240753
  • issue/automatic_updates-3233103
  • issue/automatic_updates-3240971
  • issue/automatic_updates-3233564
  • issue/automatic_updates-3241380
  • issue/automatic_updates-3241105
  • issue/automatic_updates-3242626
  • issue/automatic_updates-3242724
  • issue/automatic_updates-3243057
  • issue/automatic_updates-3243348
  • issue/automatic_updates-3243339
  • issue/automatic_updates-3243422
  • issue/automatic_updates-3243436
  • issue/automatic_updates-3243600
  • issue/automatic_updates-3243851
  • issue/automatic_updates-3243405
  • issue/automatic_updates-3244338
  • issue/automatic_updates-3244337
  • issue/automatic_updates-3244360
  • issue/automatic_updates-3244358
  • issue/automatic_updates-3244679
  • issue/automatic_updates-3244939
  • issue/automatic_updates-3244976
  • issue/automatic_updates-3245376
  • issue/automatic_updates-3245388
  • issue/automatic_updates-3245428
  • issue/automatic_updates-3245655
  • issue/automatic_updates-3245766
  • issue/automatic_updates-3245810
  • issue/automatic_updates-3245846
  • issue/automatic_updates-3246036
  • issue/automatic_updates-3246194
  • issue/automatic_updates-3246203
  • issue/automatic_updates-3246283
  • issue/automatic_updates-3279064
  • issue/automatic_updates-3246420
  • issue/automatic_updates-3246638
  • issue/automatic_updates-3246660
  • issue/automatic_updates-3246673
  • issue/automatic_updates-3246695
  • issue/automatic_updates-3245996
  • issue/automatic_updates-3247308
  • issue/automatic_updates-3247478
  • issue/automatic_updates-3247479
  • issue/automatic_updates-3279086
  • issue/automatic_updates-3248312
  • issue/automatic_updates-3248523
  • issue/automatic_updates-3248527
  • issue/automatic_updates-3244412
  • issue/automatic_updates-3248976
  • issue/automatic_updates-3248909
  • issue/automatic_updates-3246507
  • issue/automatic_updates-3249531
  • issue/automatic_updates-3249517
  • issue/automatic_updates-3249983
  • issue/automatic_updates-3249135
  • issue/automatic_updates-3250136
  • issue/automatic_updates-3250386
  • issue/automatic_updates-3251701
  • issue/automatic_updates-3250696
  • issue/automatic_updates-3248911
  • issue/automatic_updates-3227420
  • issue/automatic_updates-3252071
  • issue/automatic_updates-3252097
  • issue/automatic_updates-3252109
  • issue/automatic_updates-3252126
  • issue/automatic_updates-3249130
  • issue/automatic_updates-3251972
  • issue/automatic_updates-3252187
  • issue/automatic_updates-3252328
  • issue/automatic_updates-3252324
  • issue/automatic_updates-3252533
  • issue/automatic_updates-3253055
  • issue/automatic_updates-3253186
  • issue/automatic_updates-3253395
  • issue/automatic_updates-3253400
  • issue/automatic_updates-3253624
  • issue/automatic_updates-3253647
  • issue/automatic_updates-3253649
  • issue/automatic_updates-3253858
  • issue/automatic_updates-3254166
  • issue/automatic_updates-3254207
  • issue/automatic_updates-3279108
  • issue/automatic_updates-3254606
  • issue/automatic_updates-3254616
  • issue/automatic_updates-3254911
  • issue/automatic_updates-3255011
  • issue/automatic_updates-3255014
  • issue/automatic_updates-3255320
  • issue/automatic_updates-3277562
  • issue/automatic_updates-3255678
  • issue/automatic_updates-3256958
  • issue/automatic_updates-3257115
  • issue/automatic_updates-3257432
  • issue/automatic_updates-3257446
  • issue/automatic_updates-3257473
  • issue/automatic_updates-3257134
  • issue/automatic_updates-3257849
  • issue/automatic_updates-3258065
  • issue/automatic_updates-3258056
  • issue/automatic_updates-3258048
  • issue/automatic_updates-3258045
  • issue/automatic_updates-3258464
  • issue/automatic_updates-3258611
  • issue/automatic_updates-3258646
  • issue/automatic_updates-3258661
  • issue/automatic_updates-3258667
  • issue/automatic_updates-3258590
  • issue/automatic_updates-3259228
  • issue/automatic_updates-3259656
  • issue/automatic_updates-3252299
  • issue/automatic_updates-3259664
  • issue/automatic_updates-3259822
  • issue/automatic_updates-3259810
  • issue/automatic_updates-3259814
  • issue/automatic_updates-3260368
  • issue/automatic_updates-3257845
  • issue/automatic_updates-3260664
  • issue/automatic_updates-3260672
  • issue/automatic_updates-3260698
  • issue/automatic_updates-3260662
  • issue/automatic_updates-3260669
  • issue/automatic_updates-3260668
  • issue/automatic_updates-3261637
  • issue/automatic_updates-3261772
  • issue/automatic_updates-3261847
  • issue/automatic_updates-3262016
  • issue/automatic_updates-3262244
  • issue/automatic_updates-3262303
  • issue/automatic_updates-3261642
  • issue/automatic_updates-3262359
  • issue/automatic_updates-3262542
  • issue/automatic_updates-3261098
  • issue/automatic_updates-3260666
  • issue/automatic_updates-3262587
  • issue/automatic_updates-3262965
  • issue/automatic_updates-3263155
  • issue/automatic_updates-3263223
  • issue/automatic_updates-3254755
  • issue/automatic_updates-3261758
  • issue/automatic_updates-3258059
  • issue/automatic_updates-3259196
  • issue/automatic_updates-3263865
  • issue/automatic_updates-3262284
  • issue/automatic_updates-3264554
  • issue/automatic_updates-3248928
  • issue/automatic_updates-3248929
  • issue/automatic_updates-3265072
  • issue/automatic_updates-3265057
  • issue/automatic_updates-3265873
  • issue/automatic_updates-3266092
  • issue/automatic_updates-3266633
  • issue/automatic_updates-3266640
  • issue/automatic_updates-3266687
  • issue/automatic_updates-3266981
  • issue/automatic_updates-3267387
  • issue/automatic_updates-3267389
  • issue/automatic_updates-3267411
  • issue/automatic_updates-3267603
  • issue/automatic_updates-3265874
  • issue/automatic_updates-3267577
  • issue/automatic_updates-3267386
  • issue/automatic_updates-3268363
  • issue/automatic_updates-3268868
  • issue/automatic_updates-3268612
  • issue/automatic_updates-3269097
  • issue/automatic_updates-3267632
  • issue/automatic_updates-3270736
  • issue/automatic_updates-3271144
  • issue/automatic_updates-3271226
  • issue/automatic_updates-3271078
  • issue/automatic_updates-3271371
  • issue/automatic_updates-3267646
  • issue/automatic_updates-3272060
  • issue/automatic_updates-3265031
  • issue/automatic_updates-3253591
  • issue/automatic_updates-3272520
  • issue/automatic_updates-3272061
  • issue/automatic_updates-3272785
  • issue/automatic_updates-3273011
  • issue/automatic_updates-3273008
  • issue/automatic_updates-3273364
  • issue/automatic_updates-3273407
  • issue/automatic_updates-3271235
  • issue/automatic_updates-3273006
  • issue/automatic_updates-3271240
  • issue/automatic_updates-3271468
  • issue/automatic_updates-3272326
  • issue/automatic_updates-3273693
  • issue/automatic_updates-3264849
  • issue/automatic_updates-3273807
  • issue/automatic_updates-3273017
  • issue/automatic_updates-3274269
  • issue/automatic_updates-3274273
  • issue/automatic_updates-3274292
  • issue/automatic_updates-3273812
  • issue/automatic_updates-3274323
  • issue/automatic_updates-3274633
  • issue/automatic_updates-3274858
  • issue/automatic_updates-3274830
  • issue/automatic_updates-3274892
  • issue/automatic_updates-3275075
  • issue/automatic_updates-3275256
  • issue/automatic_updates-3275282
  • issue/automatic_updates-3275320
  • issue/automatic_updates-3275323
  • issue/automatic_updates-3275324
  • issue/automatic_updates-3275317
  • issue/automatic_updates-3275313
  • issue/automatic_updates-3275357
  • issue/automatic_updates-3275474
  • issue/automatic_updates-3275311
  • issue/automatic_updates-3275546
  • issue/automatic_updates-3275508
  • issue/automatic_updates-3275810
  • issue/automatic_updates-3275860
  • issue/automatic_updates-3275865
  • issue/automatic_updates-3275886
  • issue/automatic_updates-3275887
  • issue/automatic_updates-3276031
  • issue/automatic_updates-3276041
  • issue/automatic_updates-3276072
  • issue/automatic_updates-3276159
  • issue/automatic_updates-3276255
  • issue/automatic_updates-3275825
  • issue/automatic_updates-3276661
  • issue/automatic_updates-3275369
  • issue/automatic_updates-3277014
  • issue/automatic_updates-3277035
  • issue/automatic_updates-3272813
  • issue/automatic_updates-3277211
  • issue/automatic_updates-3277229
  • issue/automatic_updates-3275316
  • issue/automatic_updates-3274047
  • issue/automatic_updates-3277815
  • issue/automatic_updates-3276662
  • issue/automatic_updates-3277235
  • issue/automatic_updates-3278411
  • issue/automatic_updates-3278435
  • issue/automatic_updates-3279229
  • issue/automatic_updates-3277007
  • issue/automatic_updates-3284346
  • issue/automatic_updates-3239759
  • issue/automatic_updates-3284495
  • issue/automatic_updates-3284530
  • issue/automatic_updates-3282677
  • issue/automatic_updates-3281379
  • issue/automatic_updates-3285408
  • issue/automatic_updates-3285631
  • issue/automatic_updates-3285669
  • issue/automatic_updates-3273014
  • issue/automatic_updates-3273369
  • issue/automatic_updates-3285491
  • issue/automatic_updates-3285898
  • issue/automatic_updates-3287251
  • issue/automatic_updates-3291147
  • issue/automatic_updates-3286650
  • issue/automatic_updates-3291770
  • issue/automatic_updates-3280403
  • issue/automatic_updates-3291959
  • issue/automatic_updates-3287398
  • issue/automatic_updates-3285145
  • issue/automatic_updates-3292027
  • issue/automatic_updates-3278445
  • issue/automatic_updates-3292933
  • issue/automatic_updates-3292958
  • issue/automatic_updates-3293157
  • issue/automatic_updates-3292956
  • issue/automatic_updates-3293146
  • issue/automatic_updates-3293381
  • issue/automatic_updates-3293449
  • issue/automatic_updates-3293427
  • issue/automatic_updates-3293422
  • issue/automatic_updates-3293685
  • issue/automatic_updates-3291730
  • issue/automatic_updates-3293866
  • issue/automatic_updates-3294338
  • issue/automatic_updates-3293656
  • issue/automatic_updates-3294600
  • issue/automatic_updates-3294335
  • issue/automatic_updates-3295013
  • issue/automatic_updates-3284936
  • issue/automatic_updates-3295596
  • issue/automatic_updates-3295758
  • issue/automatic_updates-3295791
  • issue/automatic_updates-3295830
  • issue/automatic_updates-3295874
  • issue/automatic_updates-3295897
  • issue/automatic_updates-3296074
  • issue/automatic_updates-3295965
  • issue/automatic_updates-3296181
  • issue/automatic_updates-3296065
  • issue/automatic_updates-3296178
  • issue/automatic_updates-3296261
  • issue/automatic_updates-3293148
  • issue/automatic_updates-3303953
  • issue/automatic_updates-3304367
  • issue/automatic_updates-3304640
  • issue/automatic_updates-3304836
  • issue/automatic_updates-3304142
  • issue/automatic_updates-3298349
  • issue/automatic_updates-3298444
  • issue/automatic_updates-3298510
  • issue/automatic_updates-3298431
  • issue/automatic_updates-3298863
  • issue/automatic_updates-3298877
  • issue/automatic_updates-3298904
  • issue/automatic_updates-3298951
  • issue/automatic_updates-3299101
  • issue/automatic_updates-3299417
  • issue/automatic_updates-3293417
  • issue/automatic_updates-3299612
  • issue/automatic_updates-3299093
  • issue/automatic_updates-3299087
  • issue/automatic_updates-3300006
  • issue/automatic_updates-3300036
  • issue/automatic_updates-3293150
  • issue/automatic_updates-3303807
  • issue/automatic_updates-3303929
  • issue/automatic_updates-3304417
  • issue/automatic_updates-3303727
  • issue/automatic_updates-3305527
  • issue/automatic_updates-3301844
  • issue/automatic_updates-3302527
  • issue/automatic_updates-3302673
  • issue/automatic_updates-3302897
  • issue/automatic_updates-3303143
  • issue/automatic_updates-3303168
  • issue/automatic_updates-3303174
  • issue/automatic_updates-3303185
  • issue/automatic_updates-3303200
  • issue/automatic_updates-3303113
  • issue/automatic_updates-3304036
  • issue/automatic_updates-3304165
  • issue/automatic_updates-3304583
  • issue/automatic_updates-3303902
  • issue/automatic_updates-3304651
  • issue/automatic_updates-3305312
  • issue/automatic_updates-3305612
  • issue/automatic_updates-3305568
  • issue/automatic_updates-3305773
  • issue/automatic_updates-3305874
  • issue/automatic_updates-3310901
  • issue/automatic_updates-3310929
  • issue/automatic_updates-3310936
  • issue/automatic_updates-3310972
  • issue/automatic_updates-3311001
  • issue/automatic_updates-3311020
  • issue/automatic_updates-3305240
  • issue/automatic_updates-3305994
  • issue/automatic_updates-3305564
  • issue/automatic_updates-3305998
  • issue/automatic_updates-3306600
  • issue/automatic_updates-3306631
  • issue/automatic_updates-3307086
  • issue/automatic_updates-3307103
  • issue/automatic_updates-3307168
  • issue/automatic_updates-3306163
  • issue/automatic_updates-3304617
  • issue/automatic_updates-3307163
  • issue/automatic_updates-3307398
  • issue/automatic_updates-3307478
  • issue/automatic_updates-3307369
  • issue/automatic_updates-3308404
  • issue/automatic_updates-3307611
  • issue/automatic_updates-3308372
  • issue/automatic_updates-3308686
  • issue/automatic_updates-3308886
  • issue/automatic_updates-3309220
  • issue/automatic_updates-3309270
  • issue/automatic_updates-3308711
  • issue/automatic_updates-3309486
  • issue/automatic_updates-3305167
  • issue/automatic_updates-3309676
  • issue/automatic_updates-3309025
  • issue/automatic_updates-3309891
  • issue/automatic_updates-3308365
  • issue/automatic_updates-3310000
  • issue/automatic_updates-3309205
  • issue/automatic_updates-3248975
  • issue/automatic_updates-3310702
  • issue/automatic_updates-3272313
  • issue/automatic_updates-3310990
  • issue/automatic_updates-3310997
  • issue/automatic_updates-3311200
  • issue/automatic_updates-3310696
  • issue/automatic_updates-3311265
  • issue/automatic_updates-3303167
  • issue/automatic_updates-3310946
  • issue/automatic_updates-3308828
  • issue/automatic_updates-3310666
  • issue/automatic_updates-3109082
  • issue/automatic_updates-3311534
  • issue/automatic_updates-3311436
  • issue/automatic_updates-3308843
  • issue/automatic_updates-3303900
  • issue/automatic_updates-3312085
  • issue/automatic_updates-3312420
  • issue/automatic_updates-3312373
  • issue/automatic_updates-3312421
  • issue/automatic_updates-3312619
  • issue/automatic_updates-3312779
  • issue/automatic_updates-3275991
  • issue/automatic_updates-3312938
  • issue/automatic_updates-3312937
  • issue/automatic_updates-3312960
  • issue/automatic_updates-3312669
  • issue/automatic_updates-3312981
  • issue/automatic_updates-3313319
  • issue/automatic_updates-3313346
  • issue/automatic_updates-3310914
  • issue/automatic_updates-3317220
  • issue/automatic_updates-3317232
  • issue/automatic_updates-3317278
  • issue/automatic_updates-3317409
  • issue/automatic_updates-3317267
  • issue/automatic_updates-3317599
  • issue/automatic_updates-3317988
  • issue/automatic_updates-3318313
  • issue/automatic_updates-3313630
  • issue/automatic_updates-3313717
  • issue/automatic_updates-3313947
  • issue/automatic_updates-3313507
  • issue/automatic_updates-3276645
  • issue/automatic_updates-3313349
  • issue/automatic_updates-3314137
  • issue/automatic_updates-3314143
  • issue/automatic_updates-3304365
  • issue/automatic_updates-3317796
  • issue/automatic_updates-3317996
  • issue/automatic_updates-3316484
  • issue/automatic_updates-3313414
  • issue/automatic_updates-3314764
  • issue/automatic_updates-3314771
  • issue/automatic_updates-3314787
  • issue/automatic_updates-3314805
  • issue/automatic_updates-3314734
  • issue/automatic_updates-3298889
  • issue/automatic_updates-3314803
  • issue/automatic_updates-3315139
  • issue/automatic_updates-3314946
  • issue/automatic_updates-3315449
  • issue/automatic_updates-3315798
  • issue/automatic_updates-3315834
  • issue/automatic_updates-3309602
  • issue/automatic_updates-3316115
  • issue/automatic_updates-3316131
  • issue/automatic_updates-3316293
  • issue/automatic_updates-3316318
  • issue/automatic_updates-3310729
  • issue/automatic_updates-3315700
  • issue/automatic_updates-3316668
  • issue/automatic_updates-3316721
  • issue/automatic_updates-3306283
  • issue/automatic_updates-3316611
  • issue/automatic_updates-3316895
  • issue/automatic_updates-3317385
  • issue/automatic_updates-3318625
  • issue/automatic_updates-3318770
  • issue/automatic_updates-3318846
  • issue/automatic_updates-3318927
  • issue/automatic_updates-3318933
  • issue/automatic_updates-3319044
  • issue/automatic_updates-3319045
  • issue/automatic_updates-3325716
  • issue/automatic_updates-3324421
  • issue/automatic_updates-3320486
  • issue/automatic_updates-3320558
  • issue/automatic_updates-3321206
  • issue/automatic_updates-3326934
  • issue/automatic_updates-3320755
  • issue/automatic_updates-3328765
  • issue/automatic_updates-3325654
  • issue/automatic_updates-3325869
  • issue/automatic_updates-3277034
  • issue/automatic_updates-3328516
  • issue/automatic_updates-3322546
  • issue/automatic_updates-3320487
  • issue/automatic_updates-3320792
  • issue/automatic_updates-3320815
  • issue/automatic_updates-3320638
  • issue/automatic_updates-3321256
  • issue/automatic_updates-3321684
  • issue/automatic_updates-3325522
  • issue/automatic_updates-3326334
  • issue/automatic_updates-3328234
  • issue/automatic_updates-3328740
  • issue/automatic_updates-3316932
  • issue/automatic_updates-3321386
  • issue/automatic_updates-3321933
  • issue/automatic_updates-3321282
  • issue/automatic_updates-3326801
  • issue/automatic_updates-3327753
  • issue/automatic_updates-3328742
  • issue/automatic_updates-3322313
  • issue/automatic_updates-3322203
  • issue/automatic_updates-3322150
  • issue/automatic_updates-3322404
  • issue/automatic_updates-3321236
  • issue/automatic_updates-3321994
  • issue/automatic_updates-3322589
  • issue/automatic_updates-3321904
  • issue/automatic_updates-3316855
  • issue/automatic_updates-3322931
  • issue/automatic_updates-3322913
  • issue/automatic_updates-3323037
  • issue/automatic_updates-3322918
  • issue/automatic_updates-3323211
  • issue/automatic_updates-3323565
  • issue/automatic_updates-3320824
  • issue/automatic_updates-3320836
  • issue/automatic_updates-3329002
  • issue/automatic_updates-3321971
  • issue/automatic_updates-3299094
  • issue/automatic_updates-3248544
  • issue/automatic_updates-3330139
  • issue/automatic_updates-3330365
  • issue/automatic_updates-3330712
  • issue/automatic_updates-3318065
  • issue/automatic_updates-3331310
  • issue/automatic_updates-3322917
  • issue/automatic_updates-3330140
  • issue/automatic_updates-3323003
  • issue/automatic_updates-3331355
  • issue/automatic_updates-3334054
  • issue/automatic_updates-3323706
  • issue/automatic_updates-3331168
  • issue/automatic_updates-3343430
  • issue/automatic_updates-3344562
  • issue/automatic_updates-3345039
  • issue/automatic_updates-3344039
  • issue/automatic_updates-3345313
  • issue/automatic_updates-3331471
  • issue/automatic_updates-3334994
  • issue/automatic_updates-3327229
  • issue/automatic_updates-3343889
  • issue/automatic_updates-3344124
  • issue/automatic_updates-3344689
  • issue/automatic_updates-3316368
  • issue/automatic_updates-3345767
  • issue/automatic_updates-3317815
  • issue/automatic_updates-3328600
  • issue/automatic_updates-3332256
  • issue/automatic_updates-3335766
  • issue/automatic_updates-3335802
  • issue/automatic_updates-3335908
  • issue/automatic_updates-3336243
  • issue/automatic_updates-3336247
  • issue/automatic_updates-3336255
  • issue/automatic_updates-3336259
  • issue/automatic_updates-3337062
  • issue/automatic_updates-3337068
  • issue/automatic_updates-3311229
  • issue/automatic_updates-3337697
  • issue/automatic_updates-3343768
  • issue/automatic_updates-3344127
  • issue/automatic_updates-3344595
  • issue/automatic_updates-3345763
  • issue/automatic_updates-3345765
  • issue/automatic_updates-3345771
  • issue/automatic_updates-3337760
  • issue/automatic_updates-3337049
  • issue/automatic_updates-3342430
  • issue/automatic_updates-3319507
  • issue/automatic_updates-3344583
  • issue/automatic_updates-3345764
  • issue/automatic_updates-3345768
  • issue/automatic_updates-3338667
  • issue/automatic_updates-3339016
  • issue/automatic_updates-3343827
  • issue/automatic_updates-3344556
  • issue/automatic_updates-3338666
  • issue/automatic_updates-3345649
  • issue/automatic_updates-3339657
  • issue/automatic_updates-3339719
  • issue/automatic_updates-3338789
  • issue/automatic_updates-3340022
  • issue/automatic_updates-3340284
  • issue/automatic_updates-3340638
  • issue/automatic_updates-3316617
  • issue/automatic_updates-3341224
  • issue/automatic_updates-3337953
  • issue/automatic_updates-3339714
  • issue/automatic_updates-3341708
  • issue/automatic_updates-3341841
  • issue/automatic_updates-3326486
  • issue/automatic_updates-3321474
  • issue/automatic_updates-3341974
  • issue/automatic_updates-3342120
  • issue/automatic_updates-3342227
  • issue/automatic_updates-3323461
  • issue/automatic_updates-3342137
  • issue/automatic_updates-3342460
  • issue/automatic_updates-3342364
  • issue/automatic_updates-3345028
  • issue/automatic_updates-3345549
  • issue/automatic_updates-3345881
  • issue/automatic_updates-3345762
  • issue/automatic_updates-3342726
  • issue/automatic_updates-3337667
  • issue/automatic_updates-3343463
  • issue/automatic_updates-3345766
  • issue/automatic_updates-3345754
  • issue/automatic_updates-3345633
  • issue/automatic_updates-3345772
  • issue/automatic_updates-3345769
  • issue/automatic_updates-3345761
  • issue/automatic_updates-3345755
  • issue/automatic_updates-3345760
  • issue/automatic_updates-3345757
  • issue/automatic_updates-3346520
  • issue/automatic_updates-3346545
  • issue/automatic_updates-3337054
  • issue/automatic_updates-3346628
  • issue/automatic_updates-3346717
  • issue/automatic_updates-3346594
  • issue/automatic_updates-3346659
  • issue/automatic_updates-3347031
  • issue/automatic_updates-3346547
  • issue/automatic_updates-3347164
  • issue/automatic_updates-3318306
  • issue/automatic_updates-3345646
  • issue/automatic_updates-3347165
  • issue/automatic_updates-3347959
  • issue/automatic_updates-3347267
  • issue/automatic_updates-3338346
  • issue/automatic_updates-3348122
  • issue/automatic_updates-3348129
  • issue/automatic_updates-3348162
  • issue/automatic_updates-3348276
  • issue/automatic_updates-3348441
  • issue/automatic_updates-3351604
  • issue/automatic_updates-3316843
  • issue/automatic_updates-3351908
  • issue/automatic_updates-3352731
  • issue/automatic_updates-3352898
  • issue/automatic_updates-3348866
  • issue/automatic_updates-3342817
  • issue/automatic_updates-3348159
  • issue/automatic_updates-3349142
  • issue/automatic_updates-3349966
  • issue/automatic_updates-3350909
  • issue/automatic_updates-3351594
  • issue/automatic_updates-3351883
  • issue/automatic_updates-3351925
  • issue/automatic_updates-3352198
  • issue/automatic_updates-3334552
  • issue/automatic_updates-3342790
  • issue/automatic_updates-3345222
  • issue/automatic_updates-3351212
  • issue/automatic_updates-3351093
  • issue/automatic_updates-3351247
  • issue/automatic_updates-3351962
  • issue/automatic_updates-3345641
  • issue/automatic_updates-3338940
  • issue/automatic_updates-3343721
  • issue/automatic_updates-3351069
  • issue/automatic_updates-3353219
  • issue/automatic_updates-3159920
  • issue/automatic_updates-3352355
  • issue/automatic_updates-3341469
  • issue/automatic_updates-3354099
  • issue/automatic_updates-3339659
  • issue/automatic_updates-3354312
  • issue/automatic_updates-3351895
  • issue/automatic_updates-3354249
  • issue/automatic_updates-3353270
  • issue/automatic_updates-3354003
  • issue/automatic_updates-3355074
  • issue/automatic_updates-3355094
  • issue/automatic_updates-3355105
  • issue/automatic_updates-3355162
  • issue/automatic_updates-3355446
  • issue/automatic_updates-3355045
  • issue/automatic_updates-3355558
  • issue/automatic_updates-3355553
  • issue/automatic_updates-3354594
  • issue/automatic_updates-3355609
  • issue/automatic_updates-3354325
  • issue/automatic_updates-3356395
  • issue/automatic_updates-3356638
  • issue/automatic_updates-3356640
  • issue/automatic_updates-3354701
  • issue/automatic_updates-3355463
  • issue/automatic_updates-3356804
  • issue/automatic_updates-3357721
  • issue/automatic_updates-3357578
  • issue/automatic_updates-3357657
  • issue/automatic_updates-3304108
  • issue/automatic_updates-3357941
  • issue/automatic_updates-3358012
  • issue/automatic_updates-3345535
  • issue/automatic_updates-3354827
  • issue/automatic_updates-3358570
  • issue/automatic_updates-3358878
  • issue/automatic_updates-3355628
  • issue/automatic_updates-3358504
  • issue/automatic_updates-3357969
  • issue/automatic_updates-3359609
  • issue/automatic_updates-3359727
  • issue/automatic_updates-3359825
  • issue/automatic_updates-3359820
  • issue/automatic_updates-3360548
  • issue/automatic_updates-3357480
  • issue/automatic_updates-3360656
  • issue/automatic_updates-3360763
  • issue/automatic_updates-3360655
  • issue/automatic_updates-3355618
  • issue/automatic_updates-3349351
  • issue/automatic_updates-3362110
  • issue/automatic_updates-3362143
  • issue/automatic_updates-3362589
  • issue/automatic_updates-3349004
  • issue/automatic_updates-3362507
  • issue/automatic_updates-3362746
  • issue/automatic_updates-3362978
  • issue/automatic_updates-3363259
  • issue/automatic_updates-3363725
  • issue/automatic_updates-3363926
  • issue/automatic_updates-3363937
  • issue/automatic_updates-3364514
  • issue/automatic_updates-3284443
  • issue/automatic_updates-3363938
  • issue/automatic_updates-3364731
  • issue/automatic_updates-3364748
  • issue/automatic_updates-3364735
  • issue/automatic_updates-3364725
  • issue/automatic_updates-3359670
  • issue/automatic_updates-3365133
  • issue/automatic_updates-3365151
  • issue/automatic_updates-3365177
  • issue/automatic_updates-3364958
  • issue/automatic_updates-3365390
  • issue/automatic_updates-3365414
  • issue/automatic_updates-3346644
  • issue/automatic_updates-3366267
  • issue/automatic_updates-3366289
  • issue/automatic_updates-3366499
  • issue/automatic_updates-3365437
  • issue/automatic_updates-3354914
  • issue/automatic_updates-3253828
  • issue/automatic_updates-3345484
  • issue/automatic_updates-3352846
  • issue/automatic_updates-3368741
  • issue/automatic_updates-3406008
  • issue/automatic_updates-3406122
  • issue/automatic_updates-3370197
  • issue/automatic_updates-3366271
  • issue/automatic_updates-3364135
  • issue/automatic_updates-3370603
  • issue/automatic_updates-3400146
  • issue/automatic_updates-3406010
  • issue/automatic_updates-3404429
  • issue/automatic_updates-3371212
  • issue/automatic_updates-3371076
  • issue/automatic_updates-3372673
  • issue/automatic_updates-3368808
  • issue/automatic_updates-3374175
  • issue/automatic_updates-3374739
  • issue/automatic_updates-3374753
  • issue/automatic_updates-3375679
  • issue/automatic_updates-3377237
  • issue/automatic_updates-3377245
  • issue/automatic_updates-3378774
  • issue/automatic_updates-3378793
  • issue/automatic_updates-3360485
  • issue/automatic_updates-3380698
  • issue/automatic_updates-3375940
  • issue/automatic_updates-3381294
  • issue/automatic_updates-3381484
  • issue/automatic_updates-3382942
  • issue/automatic_updates-3383462
  • issue/automatic_updates-3383451
  • issue/automatic_updates-3384359
  • issue/automatic_updates-3384637
  • issue/automatic_updates-3375640
  • issue/automatic_updates-3386135
  • issue/automatic_updates-3386533
  • issue/automatic_updates-3387610
  • issue/automatic_updates-3387637
  • issue/automatic_updates-3387656
  • issue/automatic_updates-3389157
  • issue/automatic_updates-3388965
  • issue/automatic_updates-3387379
  • issue/automatic_updates-3390493
  • issue/automatic_updates-3308235
  • issue/automatic_updates-3391715
  • issue/automatic_updates-3392246
  • issue/automatic_updates-3393633
  • issue/automatic_updates-3379344
  • issue/automatic_updates-3394413
  • issue/automatic_updates-3394705
  • issue/automatic_updates-3394936
  • issue/automatic_updates-3363497
  • issue/automatic_updates-3395782
  • issue/automatic_updates-3341406
  • issue/automatic_updates-3311472
  • issue/automatic_updates-3397228
  • issue/automatic_updates-3352654
  • issue/automatic_updates-3398782
  • issue/automatic_updates-3399147
  • issue/automatic_updates-3399155
  • issue/automatic_updates-3406812
  • issue/automatic_updates-3408483
  • issue/automatic_updates-3408488
  • issue/automatic_updates-3408560
  • issue/automatic_updates-3437633
  • issue/automatic_updates-3408835
  • issue/automatic_updates-3408937
  • issue/automatic_updates-3409491
  • issue/automatic_updates-3409519
  • issue/automatic_updates-3377458
  • issue/automatic_updates-3437951
  • issue/automatic_updates-3409774
  • issue/automatic_updates-3410047
  • issue/automatic_updates-3411110
  • issue/automatic_updates-3411241
  • issue/automatic_updates-3411276
  • issue/automatic_updates-3411392
  • issue/automatic_updates-3411240
  • issue/automatic_updates-3412630
  • issue/automatic_updates-3413866
  • issue/automatic_updates-3414168
  • issue/automatic_updates-3415291
  • issue/automatic_updates-3415389
  • issue/automatic_updates-3415403
  • issue/automatic_updates-3416768
  • issue/automatic_updates-3417905
  • issue/automatic_updates-3420188
  • issue/automatic_updates-3421641
  • issue/automatic_updates-3424290
  • issue/automatic_updates-3426229
  • issue/automatic_updates-3426666
  • issue/automatic_updates-3426716
  • issue/automatic_updates-3428199
  • issue/automatic_updates-3436741
  • issue/automatic_updates-3441923
  • issue/automatic_updates-3428651
  • issue/automatic_updates-3441799
  • issue/automatic_updates-3443249
  • issue/automatic_updates-3428922
  • issue/automatic_updates-3441817
  • issue/automatic_updates-3429248
  • issue/automatic_updates-3440646
  • issue/automatic_updates-3437877
  • issue/automatic_updates-3445149
  • issue/automatic_updates-3429268
  • issue/automatic_updates-3442153
  • issue/automatic_updates-3438156
  • issue/automatic_updates-3436993
  • issue/automatic_updates-3437704
  • issue/automatic_updates-3432496
  • issue/automatic_updates-3440006
  • issue/automatic_updates-3435893
  • issue/automatic_updates-3441577
  • issue/automatic_updates-3437023
  • issue/automatic_updates-3432391
  • issue/automatic_updates-3432447
  • issue/automatic_updates-3432472
  • issue/automatic_updates-3432489
  • issue/automatic_updates-3432476
  • issue/automatic_updates-3435918
  • issue/automatic_updates-3439067
  • issue/automatic_updates-3437409
  • issue/automatic_updates-3449093
  • issue/automatic_updates-3449480
  • issue/automatic_updates-3449519
  • issue/automatic_updates-3449631
  • issue/automatic_updates-3449636
  • issue/automatic_updates-3449689
  • issue/automatic_updates-3449693
  • issue/automatic_updates-3450884
  • issue/automatic_updates-3452870
  • issue/automatic_updates-3453030
  • issue/automatic_updates-3455161
  • issue/automatic_updates-3459557
  • issue/automatic_updates-3462138
  • issue/automatic_updates-3462168
  • issue/automatic_updates-3462883
  • issue/automatic_updates-3463662
  • issue/automatic_updates-3463813
  • issue/automatic_updates-3446371
  • issue/automatic_updates-3465155
  • issue/automatic_updates-3340355
  • issue/automatic_updates-3467749
  • issue/automatic_updates-3473410
  • issue/automatic_updates-3441926
  • issue/automatic_updates-3474603
  • issue/automatic_updates-3484802
  • issue/automatic_updates-3498586
  • issue/automatic_updates-3499481
  • issue/automatic_updates-3498018
  • issue/automatic_updates-3506632
  • issue/automatic_updates-3511959
  • issue/automatic_updates-3511943
981 results
Show changes
Commits on Source (3)
Showing with 546 additions and 236 deletions
......@@ -4,7 +4,7 @@ services:
arguments: ['@keyvalue.expirable', '@datetime.time', 24]
automatic_updates.updater:
class: Drupal\automatic_updates\Updater
arguments: ['@state', '@string_translation','@automatic_updates.beginner', '@automatic_updates.stager', '@automatic_updates.cleaner', '@automatic_updates.committer', '@event_dispatcher', '@config.factory']
arguments: ['@state', '@string_translation','@automatic_updates.beginner', '@automatic_updates.stager', '@automatic_updates.cleaner', '@automatic_updates.committer', '@event_dispatcher', '@automatic_updates.path_locator']
automatic_updates.beginner:
class: PhpTuf\ComposerStager\Domain\Beginner
arguments:
......@@ -14,9 +14,11 @@ services:
arguments:
['@automatic_updates.composer_runner', '@automatic_updates.file_system' ]
automatic_updates.cleaner:
class: PhpTuf\ComposerStager\Domain\Cleaner
class: Drupal\automatic_updates\ComposerStager\Cleaner
arguments:
['@automatic_updates.file_system' ]
- '@automatic_updates.file_system'
- '%site.path%'
- '@automatic_updates.path_locator'
automatic_updates.committer:
class: PhpTuf\ComposerStager\Domain\Committer
arguments:
......@@ -73,7 +75,7 @@ services:
- { name: event_subscriber }
automatic_updates.staged_projects_validator:
class: Drupal\automatic_updates\Validator\StagedProjectsValidator
arguments: [ '@string_translation', '@automatic_updates.updater' ]
arguments: ['@string_translation', '@automatic_updates.path_locator']
tags:
- { name: event_subscriber }
automatic_updates.update_version_validator:
......@@ -83,6 +85,11 @@ services:
- { name: event_subscriber }
automatic_updates.composer_executable_validator:
class: Drupal\automatic_updates\Validator\ComposerExecutableValidator
arguments: ['@automatic_updates.exec_finder']
arguments: ['@automatic_updates.composer_runner']
tags:
- { name: event_subscriber }
automatic_updates.path_locator:
class: Drupal\automatic_updates\PathLocator
arguments:
- '@config.factory'
- '%app.root%'
<?php
namespace Drupal\automatic_updates\ComposerStager;
use Drupal\automatic_updates\PathLocator;
use PhpTuf\ComposerStager\Domain\Cleaner as ComposerStagerCleaner;
use PhpTuf\ComposerStager\Domain\CleanerInterface;
use PhpTuf\ComposerStager\Domain\Output\ProcessOutputCallbackInterface;
use PhpTuf\ComposerStager\Infrastructure\Filesystem\FilesystemInterface;
use Symfony\Component\Filesystem\Filesystem;
/**
* Defines a cleaner service that makes the staged site directory writable.
*/
class Cleaner implements CleanerInterface {
/**
* The decorated cleaner service.
*
* @var \PhpTuf\ComposerStager\Domain\CleanerInterface
*/
protected $decorated;
/**
* The current site path, without leading or trailing slashes.
*
* @var string
*/
protected $sitePath;
/**
* The path locator service.
*
* @var \Drupal\automatic_updates\PathLocator
*/
protected $pathLocator;
/**
* Constructs a Cleaner object.
*
* @param \PhpTuf\ComposerStager\Infrastructure\Filesystem\FilesystemInterface $file_system
* The Composer Stager file system service.
* @param string $site_path
* The current site path (e.g., 'sites/default'), without leading or
* trailing slashes.
* @param \Drupal\automatic_updates\PathLocator $locator
* The path locator service.
*/
public function __construct(FilesystemInterface $file_system, string $site_path, PathLocator $locator) {
// @todo Inject the decorated cleaner once the Composer Stager wiring has
// been moved into a separate module.
$this->decorated = new ComposerStagerCleaner($file_system);
$this->sitePath = $site_path;
$this->pathLocator = $locator;
}
/**
* {@inheritdoc}
*/
public function clean(string $stagingDir, ?ProcessOutputCallbackInterface $callback = NULL, ?int $timeout = 120): void {
// Ensure that the staged site directory is writable so we can delete it.
$site_dir = implode(DIRECTORY_SEPARATOR, [
$stagingDir,
$this->pathLocator->getWebRoot() ?: '.',
$this->sitePath,
]);
if ($this->directoryExists($site_dir)) {
(new Filesystem())->chmod($site_dir, 0777);
}
$this->decorated->clean($stagingDir, $callback, $timeout);
}
/**
* {@inheritdoc}
*/
public function directoryExists(string $stagingDir): bool {
return $this->decorated->directoryExists($stagingDir);
}
}
<?php
namespace Drupal\automatic_updates;
use Composer\Autoload\ClassLoader;
use Drupal\Component\FileSystem\FileSystem;
use Drupal\Core\Config\ConfigFactoryInterface;
/**
* Computes file system paths that are needed for automatic updates.
*/
class PathLocator {
/**
* The config factory service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The absolute path of the running Drupal code base.
*
* @var string
*/
protected $appRoot;
/**
* Constructs a PathLocator object.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory service.
* @param string $app_root
* The absolute path of the running Drupal code base.
*/
public function __construct(ConfigFactoryInterface $config_factory, string $app_root) {
$this->configFactory = $config_factory;
$this->appRoot = $app_root;
}
/**
* Returns the path of the active directory, which should be updated.
*
* @return string
* The absolute path which should be updated.
*/
public function getActiveDirectory(): string {
return $this->getProjectRoot();
}
/**
* Returns the path of the directory where updates should be staged.
*
* This directory may be made world-writeable for clean-up, so it should be
* somewhere that doesn't put the Drupal installation at risk.
*
* @return string
* The absolute path of the directory where updates should be staged.
*
* @see \Drupal\automatic_updates\ComposerStager\Cleaner::clean()
*/
public function getStageDirectory(): string {
// Append the site ID to the directory in order to support parallel test
// runs, or multiple sites hosted on the same server.
$site_id = $this->configFactory->get('system.site')->get('uuid');
return FileSystem::getOsTemporaryDirectory() . DIRECTORY_SEPARATOR . '.automatic_updates_stage_' . $site_id;
}
/**
* Returns the absolute path of the project root.
*
* This is where the project-level composer.json should normally be found, and
* may or may not be the same path as the Drupal code base.
*
* @return string
* The absolute path of the project root.
*/
public function getProjectRoot(): string {
// Assume that the vendor directory is immediately below the project root.
return realpath($this->getVendorDirectory() . DIRECTORY_SEPARATOR . '..');
}
/**
* Returns the absolute path of the vendor directory.
*
* @return string
* The absolute path of the vendor directory.
*/
public function getVendorDirectory(): string {
$reflector = new \ReflectionClass(ClassLoader::class);
return dirname($reflector->getFileName(), 2);
}
/**
* Returns the path of the Drupal installation, relative to the project root.
*
* @return string
* The path of the Drupal installation, relative to the project root and
* without leading or trailing slashes. Will return an empty string if the
* project root and Drupal root are the same.
*/
public function getWebRoot(): string {
$web_root = str_replace($this->getProjectRoot(), NULL, $this->appRoot);
return trim($web_root, DIRECTORY_SEPARATOR);
}
}
......@@ -2,14 +2,11 @@
namespace Drupal\automatic_updates;
use Composer\Autoload\ClassLoader;
use Drupal\automatic_updates\Event\PreCommitEvent;
use Drupal\automatic_updates\Event\PreStartEvent;
use Drupal\automatic_updates\Event\UpdateEvent;
use Drupal\automatic_updates\Exception\UpdateException;
use Drupal\Component\FileSystem\FileSystem;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
......@@ -77,11 +74,11 @@ class Updater {
protected $eventDispatcher;
/**
* The config factory service.
* The path locator service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
* @var \Drupal\automatic_updates\PathLocator
*/
protected $configFactory;
protected $pathLocator;
/**
* Constructs an Updater object.
......@@ -100,10 +97,10 @@ class Updater {
* The Composer Stager's committer service.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
* The event dispatcher service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory service.
* @param \Drupal\automatic_updates\PathLocator $path_locator
* The path locator service.
*/
public function __construct(StateInterface $state, TranslationInterface $translation, BeginnerInterface $beginner, StagerInterface $stager, CleanerInterface $cleaner, CommitterInterface $committer, EventDispatcherInterface $event_dispatcher, ConfigFactoryInterface $config_factory) {
public function __construct(StateInterface $state, TranslationInterface $translation, BeginnerInterface $beginner, StagerInterface $stager, CleanerInterface $cleaner, CommitterInterface $committer, EventDispatcherInterface $event_dispatcher, PathLocator $path_locator) {
$this->state = $state;
$this->beginner = $beginner;
$this->stager = $stager;
......@@ -111,31 +108,7 @@ class Updater {
$this->committer = $committer;
$this->setStringTranslation($translation);
$this->eventDispatcher = $event_dispatcher;
$this->configFactory = $config_factory;
}
/**
* Gets the vendor directory.
*
* @return string
* The absolute path for vendor directory.
*/
private static function getVendorDirectory(): string {
$class_loader_reflection = new \ReflectionClass(ClassLoader::class);
return dirname($class_loader_reflection->getFileName(), 2);
}
/**
* Gets the stage directory.
*
* @return string
* The absolute path for stage directory.
*/
public function getStageDirectory(): string {
// Append the site ID to the directory in order to support parallel test
// runs, or multiple sites hosted on the same server.
$site_id = $this->configFactory->get('system.site')->get('uuid');
return FileSystem::getOsTemporaryDirectory() . '/.automatic_updates_stage_' . $site_id;
$this->pathLocator = $path_locator;
}
/**
......@@ -145,23 +118,13 @@ class Updater {
* TRUE if there is active update, otherwise FALSE.
*/
public function hasActiveUpdate(): bool {
$staged_dir = $this->getStageDirectory();
$staged_dir = $this->pathLocator->getStageDirectory();
if (is_dir($staged_dir) || $this->state->get(static::STATE_KEY)) {
return TRUE;
}
return FALSE;
}
/**
* Gets the active directory.
*
* @return string
* The absolute path for active directory.
*/
public function getActiveDirectory(): string {
return realpath(static::getVendorDirectory() . '/..');
}
/**
* Begins the update.
*
......@@ -184,7 +147,7 @@ class Updater {
$stage_key = $this->createActiveStage($packages);
/** @var \Drupal\automatic_updates\Event\PreStartEvent $event */
$event = $this->dispatchUpdateEvent(new PreStartEvent($packages), AutomaticUpdatesEvents::PRE_START);
$this->beginner->begin(static::getActiveDirectory(), static::getStageDirectory(), $this->getExclusions($event));
$this->beginner->begin($this->pathLocator->getActiveDirectory(), $this->pathLocator->getStageDirectory(), $this->getExclusions($event));
return $stage_key;
}
......@@ -210,7 +173,7 @@ class Updater {
* detecting the core package.
*/
public function getCorePackageName(): string {
$composer = realpath(static::getVendorDirectory() . '/../composer.json');
$composer = realpath($this->pathLocator->getProjectRoot() . '/composer.json');
if (empty($composer) || !file_exists($composer)) {
throw new \RuntimeException("Could not find project-level composer.json");
......@@ -239,7 +202,7 @@ class Updater {
*/
private function getExclusions($event): array {
$make_relative = function (string $path): string {
return str_replace($this->getActiveDirectory() . '/', '', $path);
return str_replace($this->pathLocator->getActiveDirectory() . '/', '', $path);
};
return array_map($make_relative, $event->getExcludedPaths());
}
......@@ -270,15 +233,16 @@ class Updater {
public function commit(): void {
/** @var \Drupal\automatic_updates\Event\PreCommitEvent $event */
$event = $this->dispatchUpdateEvent(new PreCommitEvent(), AutomaticUpdatesEvents::PRE_COMMIT);
$this->committer->commit($this->getStageDirectory(), static::getActiveDirectory(), $this->getExclusions($event));
$this->committer->commit($this->pathLocator->getStageDirectory(), $this->pathLocator->getActiveDirectory(), $this->getExclusions($event));
}
/**
* Cleans the current update.
*/
public function clean(): void {
if (is_dir($this->getStageDirectory())) {
$this->cleaner->clean($this->getStageDirectory());
$stage_dir = $this->pathLocator->getStageDirectory();
if (is_dir($stage_dir)) {
$this->cleaner->clean($stage_dir);
}
$this->state->delete(static::STATE_KEY);
}
......@@ -293,7 +257,7 @@ class Updater {
* @see \PhpTuf\ComposerStager\Domain\StagerInterface::stage()
*/
protected function stageCommand(array $command): void {
$this->stager->stage($command, $this->getStageDirectory());
$this->stager->stage($command, $this->pathLocator->getStageDirectory());
}
/**
......
......@@ -5,30 +5,42 @@ namespace Drupal\automatic_updates\Validator;
use Drupal\automatic_updates\AutomaticUpdatesEvents;
use Drupal\automatic_updates\Event\UpdateEvent;
use Drupal\automatic_updates\Validation\ValidationResult;
use PhpTuf\ComposerStager\Exception\IOException;
use PhpTuf\ComposerStager\Infrastructure\Process\ExecutableFinderInterface;
use Drupal\Core\Extension\ExtensionVersion;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use PhpTuf\ComposerStager\Domain\Output\ProcessOutputCallbackInterface;
use PhpTuf\ComposerStager\Exception\ExceptionInterface;
use PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Validates that the Composer executable can be found.
* Validates that the Composer executable can be found in the correct version.
*/
class ComposerExecutableValidator implements EventSubscriberInterface {
class ComposerExecutableValidator implements EventSubscriberInterface, ProcessOutputCallbackInterface {
use StringTranslationTrait;
/**
* The Composer runner.
*
* @var \PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface
*/
protected $composer;
/**
* The executable finder service.
* The detected version of Composer.
*
* @var \PhpTuf\ComposerStager\Infrastructure\Process\ExecutableFinderInterface
* @var string
*/
protected $executableFinder;
protected $version;
/**
* Constructs a ComposerExecutableValidator object.
*
* @param \PhpTuf\ComposerStager\Infrastructure\Process\ExecutableFinderInterface $executable_finder
* The executable finder service.
* @param \PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface $composer
* The Composer runner.
*/
public function __construct(ExecutableFinderInterface $executable_finder) {
$this->executableFinder = $executable_finder;
public function __construct(ComposerRunnerInterface $composer) {
$this->composer = $composer;
}
/**
......@@ -39,13 +51,34 @@ class ComposerExecutableValidator implements EventSubscriberInterface {
*/
public function checkForComposerExecutable(UpdateEvent $event): void {
try {
$this->executableFinder->find('composer');
$this->composer->run(['--version'], $this);
}
catch (IOException $e) {
catch (ExceptionInterface $e) {
$error = ValidationResult::createError([
$e->getMessage(),
]);
$event->addValidationResult($error);
return;
}
if ($this->version) {
$major_version = ExtensionVersion::createFromVersionString($this->version)
->getMajorVersion();
if ($major_version < 2) {
$error = ValidationResult::createError([
$this->t('Composer 2 or later is required, but version @version was detected.', [
'@version' => $this->version,
]),
]);
$event->addValidationResult($error);
}
}
else {
$error = ValidationResult::createError([
$this->t('The Composer version could not be detected.'),
]);
$event->addValidationResult($error);
}
}
......@@ -58,4 +91,15 @@ class ComposerExecutableValidator implements EventSubscriberInterface {
];
}
/**
* {@inheritdoc}
*/
public function __invoke(string $type, string $buffer): void {
$matched = [];
// Search for a semantic version number and optional stability flag.
if (preg_match('/([0-9]+\.?){3}-?((alpha|beta|rc)[0-9]*)?/i', $buffer, $matched)) {
$this->version = $matched[0];
}
}
}
......@@ -5,7 +5,7 @@ namespace Drupal\automatic_updates\Validator;
use Drupal\automatic_updates\AutomaticUpdatesEvents;
use Drupal\automatic_updates\Event\UpdateEvent;
use Drupal\automatic_updates\Exception\UpdateException;
use Drupal\automatic_updates\Updater;
use Drupal\automatic_updates\PathLocator;
use Drupal\automatic_updates\Validation\ValidationResult;
use Drupal\Component\Serialization\Json;
use Drupal\Core\StringTranslation\StringTranslationTrait;
......@@ -20,23 +20,23 @@ final class StagedProjectsValidator implements EventSubscriberInterface {
use StringTranslationTrait;
/**
* The updater service.
* The path locator service.
*
* @var \Drupal\automatic_updates\Updater
* @var \Drupal\automatic_updates\PathLocator
*/
protected $updater;
protected $pathLocator;
/**
* Constructs a StagedProjectsValidation object.
*
* @param \Drupal\Core\StringTranslation\TranslationInterface $translation
* The translation service.
* @param \Drupal\automatic_updates\Updater $updater
* The updater service.
* @param \Drupal\automatic_updates\PathLocator $path_locator
* The path locator service.
*/
public function __construct(TranslationInterface $translation, Updater $updater) {
public function __construct(TranslationInterface $translation, PathLocator $path_locator) {
$this->setStringTranslation($translation);
$this->updater = $updater;
$this->pathLocator = $path_locator;
}
/**
......@@ -87,8 +87,8 @@ final class StagedProjectsValidator implements EventSubscriberInterface {
*/
public function validateStagedProjects(UpdateEvent $event): void {
try {
$active_packages = $this->getDrupalPackagesFromLockFile($this->updater->getActiveDirectory() . "/composer.lock");
$staged_packages = $this->getDrupalPackagesFromLockFile($this->updater->getStageDirectory() . "/composer.lock");
$active_packages = $this->getDrupalPackagesFromLockFile($this->pathLocator->getActiveDirectory() . "/composer.lock");
$staged_packages = $this->getDrupalPackagesFromLockFile($this->pathLocator->getStageDirectory() . "/composer.lock");
}
catch (UpdateException $e) {
foreach ($e->getValidationResults() as $result) {
......
<?php
namespace Drupal\automatic_updates_test;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
/**
* Modifies service definitions for testing purposes.
*/
class AutomaticUpdatesTestServiceProvider extends ServiceProviderBase {
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container) {
parent::alter($container);
$service = 'automatic_updates.updater';
if ($container->hasDefinition($service)) {
$container->getDefinition($service)->setClass(TestUpdater::class);
}
}
}
<?php
namespace Drupal\automatic_updates_test;
use Drupal\automatic_updates\Updater;
/**
* A testing updater that allows arbitrary active and stage directories.
*/
class TestUpdater extends Updater {
/**
* The active directory to use, if different from the default.
*
* @var string
*/
public $activeDirectory;
/**
* The stage directory to use, if different from the default.
*
* @var string
*/
public $stageDirectory;
/**
* {@inheritdoc}
*/
public function getActiveDirectory(): string {
return $this->activeDirectory ?: parent::getActiveDirectory();
}
/**
* {@inheritdoc}
*/
public function getStageDirectory(): string {
return $this->stageDirectory ?: parent::getStageDirectory();
}
}
<?php
namespace Drupal\Tests\automatic_updates\Functional;
use Drupal\Core\Site\Settings;
use Drupal\Tests\BrowserTestBase;
/**
* Tests exclusion of certain files and directories from the staging area.
*
* @group automatic_updates
*/
class ExclusionsTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['automatic_updates_test', 'update_test'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* Tests that certain files and directories are not staged.
*
* @covers \Drupal\automatic_updates\Updater::getExclusions
*/
public function testExclusions(): void {
$stage_dir = "$this->siteDirectory/stage";
/** @var \Drupal\automatic_updates_test\TestUpdater $updater */
$updater = $this->container->get('automatic_updates.updater');
$updater->activeDirectory = __DIR__ . '/../../fixtures/fake-site';
$updater->stageDirectory = $stage_dir;
$settings = Settings::getAll();
$settings['file_public_path'] = 'files/public';
$settings['file_private_path'] = 'files/private';
new Settings($settings);
// Updater::begin() will trigger update validators, such as
// \Drupal\automatic_updates\Event\UpdateVersionSubscriber, that need to
// fetch release metadata. We need to ensure that those HTTP request(s)
// succeed, so set them up to point to our fake release metadata.
$this->config('update_test.settings')
->set('xml_map', [
'drupal' => '0.0',
])
->save();
$this->config('update.settings')
->set('fetch.url', $this->baseUrl . '/automatic-update-test')
->save();
$this->config('update_test.settings')
->set('system_info.#all.version', '9.8.0')
->save();
$updater->begin(['drupal' => '9.8.1']);
$this->assertFileDoesNotExist("$stage_dir/sites/default/settings.php");
$this->assertFileDoesNotExist("$stage_dir/sites/default/settings.local.php");
$this->assertFileDoesNotExist("$stage_dir/sites/default/services.yml");
// A file in sites/default, that isn't one of the site-specific settings
// files, should be staged.
$this->assertFileExists("$stage_dir/sites/default/staged.txt");
$this->assertDirectoryDoesNotExist("$stage_dir/sites/simpletest");
$this->assertDirectoryDoesNotExist("$stage_dir/files/public");
$this->assertDirectoryDoesNotExist("$stage_dir/files/private");
// A file that's in the general files directory, but not in the public or
// private directories, should be staged.
$this->assertFileExists("$stage_dir/files/staged.txt");
}
}
<?php
namespace Drupal\Tests\automatic_updates\Functional;
use Drupal\automatic_updates\ComposerStager\Cleaner;
use Drupal\automatic_updates\PathLocator;
use Drupal\automatic_updates\Updater;
use Drupal\Core\Site\Settings;
use Drupal\Tests\BrowserTestBase;
/**
* Tests handling of files and directories during an update.
*
* @group automatic_updates
*/
class FileSystemOperationsTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['automatic_updates_test', 'update_test'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* The updater service under test.
*
* @var \Drupal\automatic_updates\Updater
*/
private $updater;
/**
* The full path of the staging directory.
*
* @var string
*/
protected $stageDir;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
// Create a mocked path locator that uses the fake site fixture as its
// active directory, and has a staging area within the site directory for
// this test.
$drupal_root = $this->getDrupalRoot();
/** @var \Drupal\automatic_updates\PathLocator|\Prophecy\Prophecy\ObjectProphecy $locator */
$locator = $this->prophesize(PathLocator::class);
$locator->getActiveDirectory()->willReturn(__DIR__ . '/../../fixtures/fake-site');
$this->stageDir = implode(DIRECTORY_SEPARATOR, [
$drupal_root,
$this->siteDirectory,
'stage',
]);
$locator->getStageDirectory()->willReturn($this->stageDir);
$locator->getProjectRoot()->willReturn($drupal_root);
$locator->getWebRoot()->willReturn('');
// Create a cleaner that uses 'sites/default' as its site path, since it
// will otherwise default to the site path being used for the test site,
// which doesn't exist in the fake site fixture.
$cleaner = new Cleaner(
$this->container->get('automatic_updates.file_system'),
'sites/default',
$locator->reveal()
);
$this->updater = new Updater(
$this->container->get('state'),
$this->container->get('string_translation'),
$this->container->get('automatic_updates.beginner'),
$this->container->get('automatic_updates.stager'),
$cleaner,
$this->container->get('automatic_updates.committer'),
$this->container->get('event_dispatcher'),
$locator->reveal()
);
// Use the public and private files directories in the fake site fixture.
$settings = Settings::getAll();
$settings['file_public_path'] = 'files/public';
$settings['file_private_path'] = 'files/private';
new Settings($settings);
// Updater::begin() will trigger update validators, such as
// \Drupal\automatic_updates\Validator\UpdateVersionValidator, that need to
// fetch release metadata. We need to ensure that those HTTP request(s)
// succeed, so set them up to point to our fake release metadata.
$this->config('update_test.settings')
->set('xml_map', [
'drupal' => '0.0',
])
->save();
$this->config('update.settings')
->set('fetch.url', $this->baseUrl . '/automatic-update-test')
->save();
$this->config('update_test.settings')
->set('system_info.#all.version', '9.8.0')
->save();
}
/**
* Tests that certain files and directories are not staged.
*
* @covers \Drupal\automatic_updates\Updater::getExclusions
*/
public function testExclusions(): void {
$this->updater->begin(['drupal' => '9.8.1']);
$this->assertFileDoesNotExist("$this->stageDir/sites/default/settings.php");
$this->assertFileDoesNotExist("$this->stageDir/sites/default/settings.local.php");
$this->assertFileDoesNotExist("$this->stageDir/sites/default/services.yml");
// A file in sites/default, that isn't one of the site-specific settings
// files, should be staged.
$this->assertFileExists("$this->stageDir/sites/default/staged.txt");
$this->assertDirectoryDoesNotExist("$this->stageDir/sites/simpletest");
$this->assertDirectoryDoesNotExist("$this->stageDir/files/public");
$this->assertDirectoryDoesNotExist("$this->stageDir/files/private");
// A file that's in the general files directory, but not in the public or
// private directories, should be staged.
$this->assertFileExists("$this->stageDir/files/staged.txt");
}
/**
* Tests that the staging directory is properly cleaned up.
*
* @covers \Drupal\automatic_updates\Cleaner
*/
public function testClean(): void {
$this->updater->begin(['drupal' => '9.8.1']);
// Make the staged site directory read-only, so we can test that it will be
// made writable on clean-up.
$this->assertTrue(chmod("$this->stageDir/sites/default", 0400));
$this->assertNotIsWritable("$this->stageDir/sites/default/staged.txt");
// If the site directory is not writable, this will throw an exception.
$this->updater->clean();
$this->assertDirectoryDoesNotExist($this->stageDir);
}
}
......@@ -3,10 +3,12 @@
namespace Drupal\Tests\automatic_updates\Kernel\ReadinessValidation;
use Drupal\automatic_updates\Validation\ValidationResult;
use Drupal\automatic_updates\Validator\ComposerExecutableValidator;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\automatic_updates\Traits\ValidationTestTrait;
use PhpTuf\ComposerStager\Exception\IOException;
use PhpTuf\ComposerStager\Infrastructure\Process\ExecutableFinderInterface;
use Prophecy\Argument;
/**
* @covers \Drupal\automatic_updates\Validator\ComposerExecutableValidator
......@@ -46,4 +48,104 @@ class ComposerExecutableValidatorTest extends KernelTestBase {
$this->assertValidationResultsEqual([$error], $results);
}
/**
* Data provider for ::testComposerVersionValidation().
*
* @return array[]
* Sets of arguments to pass to the test method.
*/
public function providerComposerVersionValidation(): array {
// Invalid or undetectable Composer versions will always produce the same
// error.
$invalid_version = ValidationResult::createError(['The Composer version could not be detected.']);
// Unsupported Composer versions will report the detected version number
// in the validation result, so we need a function to churn out those fake
// results for the test method.
$unsupported_version = function (string $version): ValidationResult {
return ValidationResult::createError([
"Composer 2 or later is required, but version $version was detected.",
]);
};
return [
// A valid 2.x version of Composer should not produce any errors.
[
'2.1.6',
[],
],
[
'1.10.22',
[$unsupported_version('1.10.22')],
],
[
'1.7.3',
[$unsupported_version('1.7.3')],
],
[
'2.0.0-alpha3',
[],
],
[
'2.1.0-RC1',
[],
],
[
'1.0.0-RC',
[$unsupported_version('1.0.0-RC')],
],
[
'1.0.0-beta1',
[$unsupported_version('1.0.0-beta1')],
],
[
'1.9-dev',
[$invalid_version],
],
[
'@package_version@',
[$invalid_version],
],
];
}
/**
* Tests validation of various Composer versions.
*
* @param string $reported_version
* The version of Composer that `composer --version` should report.
* @param \Drupal\automatic_updates\Validation\ValidationResult[] $expected_results
* The expected validation results.
*
* @dataProvider providerComposerVersionValidation
*/
public function testComposerVersionValidation(string $reported_version, array $expected_results): void {
// Mock the output of `composer --version`, will be passed to the validator,
// which is itself a callback function that gets called repeatedly as
// Composer produces output.
/** @var \PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface|\Prophecy\Prophecy\ObjectProphecy $runner */
$runner = $this->prophesize('\PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface');
$runner->run(['--version'], Argument::type(ComposerExecutableValidator::class))
// Whatever is passed to ::run() will be passed to this mock callback in
// $arguments, and we know exactly what that will contain: an array of
// command arguments for Composer, and the validator object.
->will(function (array $arguments) use ($reported_version) {
/** @var \Drupal\automatic_updates\Validator\ComposerExecutableValidator $validator */
$validator = $arguments[1];
// Invoke the validator (which, as mentioned, is a callback function),
// with fake output from `composer --version`. It should try to tease a
// recognized, supported version number out of this output.
$validator($validator::OUT, "Composer version $reported_version");
});
$this->container->set('automatic_updates.composer_runner', $runner->reveal());
// If the validator can't find a recognized, supported version of Composer,
// it should produce errors.
$actual_results = $this->container->get('automatic_updates.readiness_validation_manager')
->run()
->getResults();
$this->assertValidationResultsEqual($expected_results, $actual_results);
}
}
......@@ -3,7 +3,7 @@
namespace Drupal\Tests\automatic_updates\Unit;
use Drupal\automatic_updates\Event\UpdateEvent;
use Drupal\automatic_updates\Updater;
use Drupal\automatic_updates\PathLocator;
use Drupal\automatic_updates\Validator\StagedProjectsValidator;
use Drupal\Component\FileSystem\FileSystem;
use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
......@@ -26,10 +26,10 @@ class StagedProjectsValidatorTest extends UnitTestCase {
$active_dir = uniqid($prefix);
$stage_dir = uniqid($prefix);
$updater = $this->prophesize(Updater::class);
$updater->getActiveDirectory()->willReturn($active_dir);
$updater->getStageDirectory()->willReturn($stage_dir);
$validator = new StagedProjectsValidator(new TestTranslationManager(), $updater->reveal());
$locator = $this->prophesize(PathLocator::class);
$locator->getActiveDirectory()->willReturn($active_dir);
$locator->getStageDirectory()->willReturn($stage_dir);
$validator = new StagedProjectsValidator(new TestTranslationManager(), $locator->reveal());
$event = new UpdateEvent();
$validator->validateStagedProjects($event);
......@@ -56,13 +56,13 @@ class StagedProjectsValidatorTest extends UnitTestCase {
* @covers ::validateStagedProjects
*/
public function testErrors(string $fixtures_dir, string $expected_summary, array $expected_messages): void {
$updater = $this->prophesize(Updater::class);
$locator = $this->prophesize(PathLocator::class);
$this->assertNotEmpty($fixtures_dir);
$this->assertDirectoryExists($fixtures_dir);
$updater->getActiveDirectory()->willReturn("$fixtures_dir/active");
$updater->getStageDirectory()->willReturn("$fixtures_dir/staged");
$validator = new StagedProjectsValidator(new TestTranslationManager(), $updater->reveal());
$locator->getActiveDirectory()->willReturn("$fixtures_dir/active");
$locator->getStageDirectory()->willReturn("$fixtures_dir/staged");
$validator = new StagedProjectsValidator(new TestTranslationManager(), $locator->reveal());
$event = new UpdateEvent();
$validator->validateStagedProjects($event);
$results = $event->getResults();
......@@ -121,10 +121,10 @@ class StagedProjectsValidatorTest extends UnitTestCase {
*/
public function testNoErrors(): void {
$fixtures_dir = realpath(__DIR__ . '/../../fixtures/project_staged_validation/no_errors');
$updater = $this->prophesize(Updater::class);
$updater->getActiveDirectory()->willReturn("$fixtures_dir/active");
$updater->getStageDirectory()->willReturn("$fixtures_dir/staged");
$validator = new StagedProjectsValidator(new TestTranslationManager(), $updater->reveal());
$locator = $this->prophesize(PathLocator::class);
$locator->getActiveDirectory()->willReturn("$fixtures_dir/active");
$locator->getStageDirectory()->willReturn("$fixtures_dir/staged");
$validator = new StagedProjectsValidator(new TestTranslationManager(), $locator->reveal());
$event = new UpdateEvent();
$validator->validateStagedProjects($event);
$results = $event->getResults();
......@@ -137,10 +137,10 @@ class StagedProjectsValidatorTest extends UnitTestCase {
*/
public function testNoLockFile(): void {
$fixtures_dir = realpath(__DIR__ . '/../../fixtures/project_staged_validation/no_errors');
$updater = $this->prophesize(Updater::class);
$updater->getActiveDirectory()->willReturn("$fixtures_dir/active");
$updater->getStageDirectory()->willReturn("$fixtures_dir");
$validator = new StagedProjectsValidator(new TestTranslationManager(), $updater->reveal());
$locator = $this->prophesize(PathLocator::class);
$locator->getActiveDirectory()->willReturn("$fixtures_dir/active");
$locator->getStageDirectory()->willReturn("$fixtures_dir");
$validator = new StagedProjectsValidator(new TestTranslationManager(), $locator->reveal());
$event = new UpdateEvent();
$validator->validateStagedProjects($event);
$results = $event->getResults();
......