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 (6)
Showing
with 610 additions and 92 deletions
......@@ -7,7 +7,7 @@ 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\Committer;
use Drupal\package_manager_bypass\LoggingCommitter;
use Drupal\package_manager_test_validation\EventSubscriber\TestSubscriber;
/**
......@@ -38,7 +38,7 @@ class UpdateErrorTest extends UpdaterFormTestBase {
$this->checkForMetaRefresh();
$this->assertUpdateStagedTimes(1);
$assert_session->pageTextNotContains('The following dependencies will also be updated:');
Committer::setException(new \Exception('failed at committer'));
LoggingCommitter::setException(new \Exception('failed at committer'));
$page->pressButton('Continue');
$this->checkForMetaRefresh();
$assert_session->pageTextContainsOnce('An error has occurred.');
......
......@@ -50,6 +50,11 @@
*
* The stage dispatches the following events during its life cycle:
*
* - \Drupal\package_manager\Event\CollectIgnoredPathsEvent
* Dispatched before the stage directory is created and also before changes in
* the stage directory are copied to the active directory. This event may be
* dispatched multiple times during a stage's life cycle.
*
* - \Drupal\package_manager\Event\PreCreateEvent
* Dispatched before the stage directory is created. At this point, the
* stage will have recorded which user or session owns it, so another stage
......@@ -97,6 +102,17 @@
* has released its ownership. This event is dispatched only once during a
* stage's life cycle.
*
* There are some cases where there is no point for an event to trigger further
* event subscribers, in which case the event propagation should be stopped.
* For example, in a situation where Composer or Composer Stager cannot work
* at all, or a security vulnerability is detected, the event propagation must
* be stopped to prevent further event subscribers from breaking. For example,
* Package Manager stops event propagation if:
* - The stage directory is a subdirectory of the active directory.
* - No composer.json file exists in active directory.
* - Package Manager has been deliberately disabled in the current environment.
* See \Drupal\package_manager\Validator\EnvironmentSupportValidator
*
* The public API of any stage consists of the following methods:
*
* - \Drupal\package_manager\Stage::create()
......@@ -155,9 +171,13 @@
* irrelevant to Composer or Package Manager. Examples include settings.php
* and related files, public and private files, SQLite databases, and git
* repositories. Custom code can use
* \Drupal\package_manager\Event\PreCreateEvent::excludePath() to exclude a
* specific path from being copied from the active directory into the stage
* directory, or \Drupal\package_manager\Event\PreApplyEvent::excludePath() to
* exclude a specific path from being copied from the stage directory back
* into the active directory.
* \Drupal\package_manager\Stage::getIgnoredPaths() which dispatches the
* CollectIgnoredPathsEvent to collect ignored paths that are excluded from
* being copied from the active directory into the stage directory, and also
* from being copied from the stage directory back into the active directory.
*
* \Drupal\package_manager\Event\StatusCheckEvent
* Dispatched to check the status of the Drupal site and whether Package Manager
* can function properly. These checks can be performed anytime, so this event
* may be dispatched multiple times.
*/
......@@ -33,7 +33,7 @@ function package_manager_help($route_name, RouteMatchInterface $route_match) {
$output .= '<ul>';
$output .= ' <li>' . t('It does not support Drupal multi-site installations.') . '</li>';
$output .= ' <li>' . t('It does not support symlinks. If you have any, see <a href="#package-manager-faq-composer-not-found">What if it says I have symlinks in my codebase?</a>.') . '</li>';
$output .= ' <li>' . t('It only allows supported composer plugins. If you have any, see <a href="#package-manager-faq-unsupported-composer-plugin">What if it says I have unsupported composer plugins in my codebase?</a>.') . '</li>';
$output .= ' <li>' . t('It only allows supported Composer plugins. If you have any, see <a href="#package-manager-faq-unsupported-composer-plugin">What if it says I have unsupported Composer plugins in my codebase?</a>.') . '</li>';
$output .= ' <li>' . t('It does not automatically perform version control operations, e.g., with Git. Site administrators are responsible for committing updates.') . '</li>';
$output .= ' <li>' . t('It can only maintain one copy of the site at any given time. If a copy of the site already exists, another one cannot be created until the existing copy is destroyed.') . '</li>';
$output .= ' <li>' . t('It associates the temporary copy of the site with the user or session that originally created it, and only that user or session can make changes to it.') . '</li>';
......@@ -81,11 +81,22 @@ function package_manager_help($route_name, RouteMatchInterface $route_match) {
$output .= '<p>' . t('The new configuration will take effect on the next Composer install or update event. Do this to apply it immediately:') . '</p>';
$output .= '<pre><code>composer install</code></pre>';
$output .= '<h4 id="package-manager-faq-unsupported-composer-plugin">' . t('What if it says I have unsupported composer plugins in my codebase?') . '</h4>';
$output .= '<p>' . t('A fresh Drupal installation only uses supported composer plugins, but some modules or themes may depend on additional composer plugins. Please <a href=":new-issue">create a new issue</a> when you encounter this.', [
$output .= '<h4 id="package-manager-faq-unsupported-composer-plugin">' . t('What if it says I have unsupported Composer plugins in my codebase?') . '</h4>';
$output .= '<p>' . t('A fresh Drupal installation only uses supported Composer plugins, but some modules or themes may depend on additional Composer plugins. Please <a href=":new-issue">create a new issue</a> when you encounter this.', [
':new-issue' => 'https://www.drupal.org/node/add/project-issue/automatic_updates',
]) . '</p>';
$output .= '<p>' . t('It is possible to <em>trust</em> additional composer plugins, but this requires significant expertise: understanding the code of that composer plugin, what the effects on the file system are and how it affects the Package Manager module. Some composer plugins could result in a broken site!') . '</p>';
$output .= '<p>' . t('It is possible to <em>trust</em> additional Composer plugins, but this requires significant expertise: understanding the code of that Composer plugin, what the effects on the file system are and how it affects the Package Manager module. Some Composer plugins could result in a broken site!') . '</p>';
$output .= '<h4 id="package-manager-faq-composer-patches-installed-or-removed">' . t('What if it says <code>cweagans/composer-patches</code> cannot be installed/removed?') . '</h4>';
$output .= '<p>' . t('Installation or removal of <code>cweagans/composer-patches</code> via Package Manager is not support it. You can install or remove it manually by running Composer commands in your site root.') . '</p>';
$output .= '<p>' . t('To install it:') . '</p>';
$output .= '<pre><code>composer require cweagans/composer-patches</code></pre>';
$output .= '<p>' . t('To remove it:') . '</p>';
$output .= '<pre><code>composer remove cweagans/composer-patches</code></pre>';
$output .= '<h4 id="package-manager-faq-composer-patches-not-a-root-dependency">' . t('What if it says <code>cweagans/composer-patches</code> must be a root dependency?') . '</h4>';
$output .= '<p>' . t('If <code>cweagans/composer-patches</code> is installed, it must be defined as a dependency of the main project (i.e., it must be listed in the <code>require</code> or <code>require-dev</code> section of <code>composer.json</code>). You can run the following command in your site root to add it as a dependency of the main project:') . '</p>';
$output .= "<pre><code>composer require cweagans/composer-patches</code></pre>";
$output .= '<h5>' . t('Custom code') . '</h5>';
$output .= '<p>' . t('Symlinks are seldom truly necessary and should be avoided in your own code. No solution currently exists to get around them--they must be removed in order to use Automatic Updates.') . '</p>';
......
......@@ -197,6 +197,12 @@ services:
- '@file_system'
tags:
- { name: event_subscriber }
package_manager.unknown_path_excluder:
class: Drupal\package_manager\PathExcluder\UnknownPathExcluder
arguments:
- '@package_manager.path_locator'
tags:
- { name: event_subscriber }
package_manager.site_configuration_excluder:
class: Drupal\package_manager\PathExcluder\SiteConfigurationExcluder
arguments:
......@@ -234,6 +240,8 @@ services:
- { name: event_subscriber }
package_manager.validator.patches:
class: Drupal\package_manager\Validator\ComposerPatchesValidator
arguments:
- '@module_handler'
tags:
- { name: event_subscriber }
package_manager.validator.supported_releases:
......
<?php
declare(strict_types = 1);
namespace Drupal\package_manager\PathExcluder;
use Drupal\package_manager\Event\CollectIgnoredPathsEvent;
use Drupal\package_manager\PathLocator;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Excludes unknown paths from stage operations.
*
* Any paths in the root directory of the project that are NOT one of the
* following are considered unknown paths:
* 1. The vendor directory
* 2. The webroot
* 3. composer.json
* 4. composer.lock
* 5. Scaffold files as determined by the drupal/core-composer-scaffold plugin
* If web root and project root are same then nothing is excluded.
*
* @internal
* This is an internal part of Package Manager and may be changed or removed
* at any time without warning. External code should not interact with this
* class.
*/
final class UnknownPathExcluder implements EventSubscriberInterface {
use PathExclusionsTrait;
/**
* Constructs a UnknownPathExcluder object.
*
* @param \Drupal\package_manager\PathLocator $path_locator
* The path locator service.
*/
public function __construct(PathLocator $path_locator) {
$this->pathLocator = $path_locator;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
return [
CollectIgnoredPathsEvent::class => 'excludeUnknownPaths',
];
}
/**
* Excludes unknown paths from stage operations.
*
* @param \Drupal\package_manager\Event\CollectIgnoredPathsEvent $event
* The event object.
*/
public function excludeUnknownPaths(CollectIgnoredPathsEvent $event): void {
$project_root = $this->pathLocator->getProjectRoot();
$web_root = $project_root . DIRECTORY_SEPARATOR . $this->pathLocator->getWebRoot();
if (realpath($web_root) === $project_root) {
return;
}
$vendor_dir = $this->pathLocator->getVendorDirectory();
// @todo Refactor in https://www.drupal.org/project/automatic_updates/issues/3334994.
$core_packages = $event->getStage()->getActiveComposer()->getCorePackages();
$scaffold_files_paths = $this->getScaffoldFiles($core_packages);
$paths_in_project_root = glob("$project_root/*");
$paths = [];
$known_paths = array_merge([$vendor_dir, $web_root, "$project_root/composer.json", "$project_root/composer.lock"], $scaffold_files_paths);
foreach ($paths_in_project_root as $path_in_project_root) {
if (!in_array($path_in_project_root, $known_paths, TRUE)) {
$paths[] = $path_in_project_root;
}
}
$this->excludeInProjectRoot($event, $paths);
}
/**
* Gets the path of scaffold files, for example 'index.php' and 'robots.txt'.
*
* @param string[] $core_packages
* The installed core packages.
*
* @return array
* The array of scaffold file paths.
*/
private function getScaffoldFiles(array $core_packages): array {
$scaffold_file_paths = [];
/** @var \Composer\Package\PackageInterface $package */
foreach ($core_packages as $package) {
$core_composer_extra = $package->getExtra();
if (array_key_exists('drupal-scaffold', $core_composer_extra)) {
$scaffold_file_paths = array_merge($scaffold_file_paths, array_keys($core_composer_extra['drupal-scaffold']['file-mapping']));
}
}
return $scaffold_file_paths;
}
}
......@@ -105,7 +105,11 @@ class ComposerExecutableValidator implements EventSubscriberInterface {
$this->composerIsAvailable->assertIsFulfilled($active_dir, $stage_dir);
}
catch (PreconditionException $e) {
$event->addError([$e->getMessage()]);
if (!$this->moduleHandler->moduleExists('help')) {
$event->addErrorFromThrowable($e);
return;
}
$this->setError($e->getMessage(), $event);
return;
}
......@@ -113,6 +117,10 @@ class ComposerExecutableValidator implements EventSubscriberInterface {
$output = $this->runCommand();
}
catch (ExceptionInterface $e) {
if (!$this->moduleHandler->moduleExists('help')) {
$event->addErrorFromThrowable($e);
return;
}
$this->setError($e->getMessage(), $event);
return;
}
......
......@@ -4,7 +4,11 @@ declare(strict_types = 1);
namespace Drupal\package_manager\Validator;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\package_manager\ComposerUtility;
use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\PreOperationStageEvent;
......@@ -13,30 +17,152 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Validates the configuration of the cweagans/composer-patches plugin.
*
* To ensure that applied patches remain consistent between the active and
* stage directories, the following rules are enforced if the patcher is
* installed:
* - It must be installed in both places, or in neither of them. It can't, for
* example, be installed in the active directory but not the stage directory
* (or vice-versa).
* - It must be one of the project's direct runtime or dev dependencies.
* - It cannot be installed or removed by Package Manager. In other words, it
* must be added to the project at the command line by someone technical
* enough to install and configure it properly.
*
* @internal
* This is an internal part of Package Manager and may be changed or removed
* at any time without warning. External code should not interact with this
* class.
*/
class ComposerPatchesValidator implements EventSubscriberInterface {
final class ComposerPatchesValidator implements EventSubscriberInterface {
use StringTranslationTrait;
/**
* {@inheritdoc}
* The name of the plugin being analyzed.
*
* @var string
*/
private const PLUGIN_NAME = 'cweagans/composer-patches';
/**
* The module handler service.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
private ModuleHandlerInterface $moduleHandler;
/**
* Constructs a ComposerPatchesValidator object.
*
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler service.
*/
public function __construct(ModuleHandlerInterface $module_handler) {
$this->moduleHandler = $module_handler;
}
/**
* Validates the status of the patcher plugin.
*
* @param \Drupal\package_manager\Event\PreOperationStageEvent $event
* The event object.
*/
public function validateStagePreOperation(PreOperationStageEvent $event): void {
public function validatePatcher(PreOperationStageEvent $event): void {
$messages = [];
$stage = $event->getStage();
$composer = $stage->getActiveComposer();
if (array_key_exists('cweagans/composer-patches', $composer->getInstalledPackages())) {
$composer = $composer->getComposer();
$extra = $composer->getPackage()->getExtra();
if (empty($extra['composer-exit-on-patch-failure'])) {
$event->addError([
$this->t('The <code>cweagans/composer-patches</code> plugin is installed, but the <code>composer-exit-on-patch-failure</code> key is not set to <code>true</code> in the <code>extra</code> section of @file.', [
'@file' => $composer->getConfig()->getConfigSource()->getName(),
]),
]);
[$plugin_installed_in_active, $is_active_root_requirement, $active_configuration_ok] = $this->computePatcherStatus($stage->getActiveComposer());
try {
[$plugin_installed_in_stage, $is_stage_root_requirement, $stage_configuration_ok] = $this->computePatcherStatus($stage->getStageComposer());
$has_staged_update = TRUE;
}
catch (\LogicException $e) {
// No staged update exists.
$has_staged_update = FALSE;
}
// If there's a staged update and the patcher has been installed or removed
// in the stage directory, that's a problem.
if ($has_staged_update && $plugin_installed_in_active !== $plugin_installed_in_stage) {
if ($plugin_installed_in_stage) {
$message = $this->t('It cannot be installed by Package Manager.');
}
else {
$message = $this->t('It cannot be removed by Package Manager.');
}
$messages[] = $this->createErrorMessage($message, 'package-manager-faq-composer-patches-installed-or-removed');
}
// If the patcher is not listed in the runtime or dev dependencies, that's
// an error as well.
if (($plugin_installed_in_active && !$is_active_root_requirement) || ($has_staged_update && $plugin_installed_in_stage && !$is_stage_root_requirement)) {
$messages[] = $this->createErrorMessage($this->t('It must be a root dependency.'), 'package-manager-faq-composer-patches-not-a-root-dependency');
}
// If the plugin is misconfigured in either the active or stage directories,
// flag an error.
if (($plugin_installed_in_active && !$active_configuration_ok) || ($has_staged_update && $plugin_installed_in_stage && !$stage_configuration_ok)) {
$messages[] = $this->t('The <code>composer-exit-on-patch-failure</code> key is not set to <code>true</code> in the <code>extra</code> section of <code>composer.json</code>.');
}
if ($messages) {
$summary = $this->t("Problems detected related to the Composer plugin <code>@plugin</code>.", [
'@plugin' => static::PLUGIN_NAME,
]);
$event->addError($messages, $summary);
}
}
/**
* Appends a link to online help to an error message.
*
* @param \Drupal\Core\StringTranslation\TranslatableMarkup $message
* The error message.
* @param string $fragment
* The fragment of the online help to link to.
*
* @return \Drupal\Core\StringTranslation\TranslatableMarkup
* The final, translated error message.
*/
private function createErrorMessage(TranslatableMarkup $message, string $fragment): TranslatableMarkup {
if ($this->moduleHandler->moduleExists('help')) {
$url = Url::fromRoute('help.page', ['name' => 'package_manager'])
->setOption('fragment', $fragment)
->toString();
return $this->t('@message See <a href=":url">the help page</a> for information on how to resolve the problem.', [
'@message' => $message,
':url' => $url,
]);
}
return $message;
}
/**
* Computes the status of the patcher plugin in a particular directory.
*
* @param \Drupal\package_manager\ComposerUtility $composer
* A Composer utility for a specific directory.
*
* @return bool[]
* An indexed array containing three booleans, in order:
* - Whether the patcher plugin is installed.
* - Whether the patcher plugin is a root requirement in composer.json (in
* either the runtime or dev dependencies).
* - Whether the `composer-exit-on-patch-failure` flag is set in the `extra`
* section of composer.json.
*/
private function computePatcherStatus(ComposerUtility $composer): array {
$is_installed = array_key_exists(static::PLUGIN_NAME, $composer->getInstalledPackages());
$root_package = $composer->getComposer()->getPackage();
$is_root_requirement = array_key_exists(static::PLUGIN_NAME, $root_package->getRequires()) || array_key_exists(static::PLUGIN_NAME, $root_package->getDevRequires());
$extra = $root_package->getExtra();
$exit_on_failure = !empty($extra['composer-exit-on-patch-failure']);
return [$is_installed, $is_root_requirement, $exit_on_failure];
}
/**
......@@ -44,9 +170,9 @@ class ComposerPatchesValidator implements EventSubscriberInterface {
*/
public static function getSubscribedEvents(): array {
return [
PreCreateEvent::class => 'validateStagePreOperation',
PreApplyEvent::class => 'validateStagePreOperation',
StatusCheckEvent::class => 'validateStagePreOperation',
PreCreateEvent::class => 'validatePatcher',
PreApplyEvent::class => 'validatePatcher',
StatusCheckEvent::class => 'validatePatcher',
];
}
......
......@@ -45,6 +45,14 @@
"options": {
"symlink": false
}
},
"cweagans/composer-patches": {
"type": "path",
"version": "24.12.1999",
"url": "../path_repos/cweagans--composer-patches",
"options": {
"symlink": false
}
}
},
"minimum-stability": "stable",
......
{
"name": "cweagans/composer-patches",
"type": "composer-plugin",
"extra": {
"class": "\\cweagans\\Fake\\ComposerPatches"
},
"require": {
"composer-plugin-api": "^1.0 || ^2.0"
},
"autoload": {
"psr-4": {"cweagans\\Fake\\": "src"}
}
}
<?php
namespace cweagans\Fake;
use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;
/**
* Dummy composer plugin implementation.
*/
class ComposerPatches implements PluginInterface {
/**
* {@inheritdoc}
*/
public function activate(Composer $composer, IOInterface $io) {}
/**
* {@inheritdoc}
*/
public function deactivate(Composer $composer, IOInterface $io) {}
/**
* {@inheritdoc}
*/
public function uninstall(Composer $composer, IOInterface $io) {}
}
name: 'Package Manager Bypass'
description: 'Mocks Package Manager services for functional testing.'
description: 'Mocks PathLocator service, decorates Beginner & Committer services (adds logging) and by default bypasses the Stager service (to minimize I/O during tests).'
type: module
package: Testing
dependencies:
......
services:
package_manager_bypass.beginner:
class: Drupal\package_manager_bypass\Beginner
class: Drupal\package_manager_bypass\LoggingBeginner
arguments: ['@state', '@package_manager_bypass.beginner.inner' ]
decorates: 'package_manager.beginner'
package_manager_bypass.committer:
class: Drupal\package_manager_bypass\Committer
class: Drupal\package_manager_bypass\LoggingCommitter
arguments: [ '@state', '@package_manager_bypass.committer.inner' ]
decorates: 'package_manager.committer'
......@@ -12,9 +12,13 @@ use PhpTuf\ComposerStager\Domain\Value\Path\PathInterface;
use PhpTuf\ComposerStager\Domain\Value\PathList\PathListInterface;
/**
* Defines a service that decorates the Composer Stager beginner service.
* A composer-stager Beginner decorator that adds logging.
*
* @internal
*/
class Beginner extends BypassedStagerServiceBase implements BeginnerInterface {
final class LoggingBeginner implements BeginnerInterface {
use LoggingDecoratorTrait;
/**
* The decorated service.
......
......@@ -12,9 +12,13 @@ use PhpTuf\ComposerStager\Domain\Value\Path\PathInterface;
use PhpTuf\ComposerStager\Domain\Value\PathList\PathListInterface;
/**
* Defines a service that decorates the Composer Stager committer service.
* A composer-stager Committer decorator that adds logging.
*
* @internal
*/
class Committer extends BypassedStagerServiceBase implements CommitterInterface {
final class LoggingCommitter implements CommitterInterface {
use LoggingDecoratorTrait;
/**
* The decorated service.
......
......@@ -10,8 +10,10 @@ namespace Drupal\package_manager_bypass;
* This can be used by functional tests to ensure that the bypassed Composer
* Stager services were called as expected. Kernel and unit tests should use
* regular mocks instead.
*
* @internal
*/
abstract class BypassedStagerServiceBase {
trait LoggingDecoratorTrait {
/**
* The state service.
......
......@@ -9,9 +9,11 @@ use Drupal\package_manager\PathLocator as BasePathLocator;
use Drupal\package_manager\Path;
/**
* Overrides the path locator to return pre-set values for testing purposes.
* Mock path locator: allows specifying paths instead of discovering paths.
*
* @internal
*/
class PathLocator extends BasePathLocator {
final class MockPathLocator extends BasePathLocator {
/**
* The state service.
......
......@@ -12,9 +12,22 @@ use PhpTuf\ComposerStager\Domain\Service\ProcessRunner\ProcessRunnerInterface;
use PhpTuf\ComposerStager\Domain\Value\Path\PathInterface;
/**
* Defines an update stager which doesn't actually do anything.
* A composer-stager Stager implementation that does nothing, except logging.
*
* By default, it will modify composer.lock in the stage directory, to fool the
* \Drupal\package_manager\Validator\LockFileValidator into thinking that there
* are pending composer operations.
*
* Opt out of this by calling @code setLockFileShouldChange(FALSE) @endcode.
*
* @see ::setLockFileShouldChange()
* @see \Drupal\package_manager\Validator\LockFileValidator
*
* @internal
*/
class Stager extends BypassedStagerServiceBase implements StagerInterface {
final class NoOpStager implements StagerInterface {
use LoggingDecoratorTrait;
/**
* Constructs a Stager object.
......
......@@ -11,8 +11,10 @@ use Symfony\Component\DependencyInjection\Reference;
/**
* Defines services to bypass Package Manager's core functionality.
*
* @internal
*/
class PackageManagerBypassServiceProvider extends ServiceProviderBase {
final class PackageManagerBypassServiceProvider extends ServiceProviderBase {
/**
* {@inheritdoc}
......@@ -21,12 +23,15 @@ class PackageManagerBypassServiceProvider extends ServiceProviderBase {
parent::alter($container);
$state = new Reference('state');
// By default, \Drupal\package_manager_bypass\NoOpStager is applied, except
// when a test opts out by setting this setting to FALSE.
// @see \Drupal\package_manager_bypass\NoOpStager::setLockFileShouldChange()
if (Settings::get('package_manager_bypass_composer_stager', TRUE)) {
$container->getDefinition('package_manager.stager')->setClass(Stager::class)->setArguments([$state]);
$container->getDefinition('package_manager.stager')->setClass(NoOpStager::class)->setArguments([$state]);
}
$definition = $container->getDefinition('package_manager.path_locator')
->setClass(PathLocator::class);
->setClass(MockPathLocator::class);
$arguments = $definition->getArguments();
array_unshift($arguments, $state);
$definition->setArguments($arguments);
......
......@@ -4,10 +4,12 @@ declare(strict_types = 1);
namespace Drupal\Tests\package_manager\Kernel;
use Drupal\Core\Url;
use Drupal\fixture_manipulator\ActiveFixtureManipulator;
use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\StatusCheckEvent;
use Drupal\package_manager\ValidationResult;
use Symfony\Component\Process\Process;
/**
* @covers \Drupal\package_manager\Validator\ComposerPatchesValidator
......@@ -16,63 +18,227 @@ use Drupal\package_manager\ValidationResult;
*/
class ComposerPatchesValidatorTest extends PackageManagerKernelTestBase {
/**
* Data provider for testErrorDuringPreCreate().
*
* @return mixed[][]
* The test cases.
*/
public function providerPatcherConfiguration(): array {
return [
'exit-on-patch-failure missing' => [
FALSE,
[
ValidationResult::createError([
t('The <code>composer-exit-on-patch-failure</code> key is not set to <code>true</code> in the <code>extra</code> section of <code>composer.json</code>.'),
], t('Problems detected related to the Composer plugin <code>cweagans/composer-patches</code>.')),
],
],
'exit-on-patch-failure set' => [
TRUE,
[],
],
];
}
/**
* Tests that the patcher configuration is validated during pre-create.
*
* @param bool $extra_key_set
* Whether to set key in extra part of root package.
* @param \Drupal\package_manager\ValidationResult[] $expected_results
* The expected validation results.
*
* @dataProvider providerPatcherConfiguration()
*/
public function testError(): void {
// Simulate an active directory where the patcher is installed, but there's
// no composer-exit-on-patch-failure flag.
$dir = $this->container->get('package_manager.path_locator')
->getProjectRoot();
$this->installPatcherInActive($dir);
// Because ComposerUtility reads composer.json and passes it to the Composer
// factory as an array, Composer will assume that the configuration is
// coming from a config.json file, even if one doesn't exist.
$error = ValidationResult::createError([
t('The <code>cweagans/composer-patches</code> plugin is installed, but the <code>composer-exit-on-patch-failure</code> key is not set to <code>true</code> in the <code>extra</code> section of @dir/composer.json.', [
'@dir' => realpath($dir),
]),
]);
$this->assertStatusCheckResults([$error]);
$this->assertResults([$error], PreCreateEvent::class);
public function testPatcherConfiguration(bool $extra_key_set, array $expected_results): void {
$this->addPatcherToAllowedPlugins();
$this->setRootRequires();
if ($extra_key_set) {
$this->setRootExtra();
}
$this->assertStatusCheckResults($expected_results);
$this->assertResults($expected_results, PreCreateEvent::class);
}
/**
* Tests that the patcher configuration is validated during pre-apply.
* Data provider for testErrorDuringPreApply() and testHelpLink().
*
* @return mixed[][]
* The test cases.
*/
public function testErrorDuringPreApply(): void {
// Simulate an active directory where the patcher is installed, but there's
// no composer-exit-on-patch-failure flag.
$dir = $this->container->get('package_manager.path_locator')
->getProjectRoot();
$this->addEventTestListener(function () use ($dir): void {
$this->installPatcherInActive($dir);
});
// Because ComposerUtility reads composer.json and passes it to the Composer
// factory as an array, Composer will assume that the configuration is
// coming from a config.json file, even if one doesn't exist.
$error = ValidationResult::createError([
"The <code>cweagans/composer-patches</code> plugin is installed, but the <code>composer-exit-on-patch-failure</code> key is not set to <code>true</code> in the <code>extra</code> section of $dir/composer.json.",
]);
$this->assertResults([$error], PreApplyEvent::class);
public function providerErrorDuringPreApply(): array {
$summary = t('Problems detected related to the Composer plugin <code>cweagans/composer-patches</code>.');
return [
'composer-patches present in stage, but not present in active' => [
FALSE,
TRUE,
[
ValidationResult::createError([
t('It cannot be installed by Package Manager.'),
t('It must be a root dependency.'),
t('The <code>composer-exit-on-patch-failure</code> key is not set to <code>true</code> in the <code>extra</code> section of <code>composer.json</code>.'),
], $summary),
],
[
'package-manager-faq-composer-patches-installed-or-removed',
'package-manager-faq-composer-patches-not-a-root-dependency',
NULL,
],
],
'composer-patches removed in stage, but present in active' => [
TRUE,
FALSE,
[
ValidationResult::createError([
t('It cannot be removed by Package Manager.'),
], $summary),
],
[
'package-manager-faq-composer-patches-installed-or-removed',
],
],
'composer-patches present in stage and active' => [
TRUE,
TRUE,
[],
[],
],
'composer-patches not present in stage and active' => [
FALSE,
FALSE,
[],
[],
],
];
}
/**
* Simulates that the patcher is installed in the active directory.
* Tests the patcher's presence and configuration are validated on pre-apply.
*
* @param string $dir
* The active directory.
* @param bool $in_active
* Whether patcher is installed in active.
* @param bool $in_stage
* Whether patcher is installed in stage.
* @param \Drupal\package_manager\ValidationResult[] $expected_results
* The expected validation results.
*
* @dataProvider providerErrorDuringPreApply
*/
private function installPatcherInActive(string $dir): void {
public function testErrorDuringPreApply(bool $in_active, bool $in_stage, array $expected_results): void {
if ($in_active) {
// Add patcher as a root dependency and set
// `composer-exit-on-patch-failure` to true.
$this->addPatcherToAllowedPlugins();
$this->setRootRequires();
$this->setRootExtra();
}
if ($in_stage && !$in_active) {
// Simulate a stage directory where the patcher is installed.
$this->getStageFixtureManipulator()
->addPackage([
'name' => 'cweagans/composer-patches',
'version' => '24.12.1999',
'type' => 'composer-plugin',
]);
}
if (!$in_stage && $in_active) {
$this->getStageFixtureManipulator()
->removePackage('cweagans/composer-patches');
}
$stage = $this->createStage();
$stage->create();
$stage_dir = $stage->getStageDirectory();
$stage->require(['drupal/core:9.8.1']);
$event = new StatusCheckEvent($stage, []);
$this->container->get('event_dispatcher')->dispatch($event);
$this->assertValidationResultsEqual($expected_results, $event->getResults(), NULL, $stage_dir);
try {
$stage->apply();
// If we didn't get an exception, ensure we didn't expect any errors
$this->assertSame([], $expected_results);
}
catch (TestStageValidationException $e) {
$this->assertNotEmpty($expected_results);
$this->assertValidationResultsEqual($expected_results, $e->getResults(), NULL, $stage_dir);
}
}
/**
* Tests that validation errors can carry links to help.
*
* @param bool $in_active
* Whether patcher is installed in active.
* @param bool $in_stage
* Whether patcher is installed in stage.
* @param \Drupal\package_manager\ValidationResult[] $expected_results
* The expected validation results.
* @param string[] $help_page_sections
* An associative array of fragments (anchors) in the online help. The keys
* should be the numeric indices of the validation result messages which
* should link to those fragments.
*
* @dataProvider providerErrorDuringPreApply
*/
public function testErrorDuringPreApplyWithHelp(bool $in_active, bool $in_stage, array $expected_results, array $help_page_sections): void {
$this->enableModules(['help']);
foreach ($expected_results as $result_index => $result) {
$messages = $result->getMessages();
foreach ($messages as $message_index => $message) {
if ($help_page_sections[$message_index]) {
// Get the link to the online documentation for the error message.
$url = Url::fromRoute('help.page', ['name' => 'package_manager'])
->setOption('fragment', $help_page_sections[$message_index])
->toString();
// Reformat the provided results so that they all have the link to the
// online documentation appended to them.
$messages[$message_index] = $message . ' See <a href="' . $url . '">the help page</a> for information on how to resolve the problem.';
}
}
$expected_results[$result_index] = ValidationResult::createError($messages, $result->getSummary());
}
$this->testErrorDuringPreApply($in_active, $in_stage, $expected_results);
}
/**
* Add the installed patcher to allowed plugins.
*/
private function addPatcherToAllowedPlugins(): void {
(new ActiveFixtureManipulator())
->addPackage([
'name' => 'cweagans/composer-patches',
'version' => '1.0.0',
'type' => 'composer-plugin',
])->commitChanges();
->addConfig([
'allow-plugins' => [
'cweagans/composer-patches' => TRUE,
],
])
->commitChanges();
}
/**
* Sets the cweagans/composer-patches as required package for root package.
*/
private function setRootRequires(): void {
$process = new Process(
['composer', 'require', "cweagans/composer-patches:@dev"],
$this->container->get('package_manager.path_locator')->getProjectRoot()
);
$process->mustRun();
}
/**
* Sets the composer-exit-on-patch-failure key in extra part of root package.
*/
private function setRootExtra(): void {
$process = new Process(
['composer', 'config', 'extra.composer-exit-on-patch-failure', 'true'],
$this->container->get('package_manager.path_locator')->getProjectRoot()
);
$process->mustRun();
}
}
......@@ -9,7 +9,7 @@ use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\PreRequireEvent;
use Drupal\package_manager\Validator\LockFileValidator;
use Drupal\package_manager\ValidationResult;
use Drupal\package_manager_bypass\Stager;
use Drupal\package_manager_bypass\NoOpStager;
/**
* @coversDefaultClass \Drupal\package_manager\Validator\LockFileValidator
......@@ -137,7 +137,7 @@ class LockFileValidatorTest extends PackageManagerKernelTestBase {
*/
public function testApplyWithNoChange(): void {
// Leave the staged lock file alone.
Stager::setLockFileShouldChange(FALSE);
NoOpStager::setLockFileShouldChange(FALSE);
$result = ValidationResult::createError([
t('There are no pending Composer operations.'),
......