Skip to content
Snippets Groups Projects

Compare revisions

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

Source

Select target project
No results found

Target

Select target project
  • project/automatic_updates
  • issue/automatic_updates-3159719
  • issue/automatic_updates-3227923
  • issue/automatic_updates-3227927
  • issue/automatic_updates-3227122
  • issue/automatic_updates-3227940
  • issue/automatic_updates-3228095
  • issue/automatic_updates-3228101
  • issue/automatic_updates-3228115
  • issue/automatic_updates-3228125
  • issue/automatic_updates-3228359
  • issue/automatic_updates-3228392
  • issue/automatic_updates-3225753
  • issue/automatic_updates-3227588
  • issue/automatic_updates-3228521
  • issue/automatic_updates-3228539
  • issue/automatic_updates-3226570
  • issue/automatic_updates-3228806
  • issue/automatic_updates-3227575
  • issue/automatic_updates-3229485
  • issue/automatic_updates-3228955
  • issue/automatic_updates-3230024
  • issue/automatic_updates-3230250
  • issue/automatic_updates-3230249
  • issue/automatic_updates-3230264
  • issue/automatic_updates-3230510
  • issue/automatic_updates-3230235
  • issue/automatic_updates-3230050
  • issue/automatic_updates-3230934
  • issue/automatic_updates-3230049
  • issue/automatic_updates-3230507
  • issue/automatic_updates-3231153
  • issue/automatic_updates-3231992
  • issue/automatic_updates-3232003
  • issue/automatic_updates-3232004
  • issue/automatic_updates-3231996
  • issue/automatic_updates-3231999
  • issue/automatic_updates-3230668
  • issue/automatic_updates-3232000
  • issue/automatic_updates-3232420
  • issue/automatic_updates-3232729
  • issue/automatic_updates-3232761
  • issue/automatic_updates-3231997
  • issue/automatic_updates-3232927
  • issue/automatic_updates-3232959
  • issue/automatic_updates-3233124
  • issue/automatic_updates-3230856
  • issue/automatic_updates-3233493
  • issue/automatic_updates-3233587
  • issue/automatic_updates-3233521
  • issue/automatic_updates-3236405
  • issue/automatic_updates-3236299
  • issue/automatic_updates-3238586
  • issue/automatic_updates-3238647
  • issue/automatic_updates-3238717
  • issue/automatic_updates-3238846
  • issue/automatic_updates-3238852
  • issue/automatic_updates-3238866
  • issue/automatic_updates-3238714
  • issue/automatic_updates-3239103
  • issue/automatic_updates-3233138
  • issue/automatic_updates-3239466
  • issue/automatic_updates-3239645
  • issue/automatic_updates-3239673
  • issue/automatic_updates-3277775
  • issue/automatic_updates-3280923
  • issue/automatic_updates-3275315
  • issue/automatic_updates-3279527
  • issue/automatic_updates-3279733
  • issue/automatic_updates-3281405
  • issue/automatic_updates-3281397
  • issue/automatic_updates-3280204
  • issue/automatic_updates-3277817
  • issue/automatic_updates-3277230
  • issue/automatic_updates-3276534
  • issue/automatic_updates-3279538
  • issue/automatic_updates-3280168
  • issue/automatic_updates-3271502
  • issue/automatic_updates-3283644
  • issue/automatic_updates-3302524
  • issue/automatic_updates-3275883
  • issue/automatic_updates-3280180
  • issue/automatic_updates-3274837
  • issue/automatic_updates-3281473
  • issue/automatic_updates-3281634
  • issue/automatic_updates-3239889
  • issue/automatic_updates-3240753
  • issue/automatic_updates-3233103
  • issue/automatic_updates-3240971
  • issue/automatic_updates-3233564
  • issue/automatic_updates-3241380
  • issue/automatic_updates-3241105
  • issue/automatic_updates-3242626
  • issue/automatic_updates-3242724
  • issue/automatic_updates-3243057
  • issue/automatic_updates-3243348
  • issue/automatic_updates-3243339
  • issue/automatic_updates-3243422
  • issue/automatic_updates-3243436
  • issue/automatic_updates-3243600
  • issue/automatic_updates-3243851
  • issue/automatic_updates-3243405
  • issue/automatic_updates-3244338
  • issue/automatic_updates-3244337
  • issue/automatic_updates-3244360
  • issue/automatic_updates-3244358
  • issue/automatic_updates-3244679
  • issue/automatic_updates-3244939
  • issue/automatic_updates-3244976
  • issue/automatic_updates-3245376
  • issue/automatic_updates-3245388
  • issue/automatic_updates-3245428
  • issue/automatic_updates-3245655
  • issue/automatic_updates-3245766
  • issue/automatic_updates-3245810
  • issue/automatic_updates-3245846
  • issue/automatic_updates-3246036
  • issue/automatic_updates-3246194
  • issue/automatic_updates-3246203
  • issue/automatic_updates-3246283
  • issue/automatic_updates-3279064
  • issue/automatic_updates-3246420
  • issue/automatic_updates-3246638
  • issue/automatic_updates-3246660
  • issue/automatic_updates-3246673
  • issue/automatic_updates-3246695
  • issue/automatic_updates-3245996
  • issue/automatic_updates-3247308
  • issue/automatic_updates-3247478
  • issue/automatic_updates-3247479
  • issue/automatic_updates-3279086
  • issue/automatic_updates-3248312
  • issue/automatic_updates-3248523
  • issue/automatic_updates-3248527
  • issue/automatic_updates-3244412
  • issue/automatic_updates-3248976
  • issue/automatic_updates-3248909
  • issue/automatic_updates-3246507
  • issue/automatic_updates-3249531
  • issue/automatic_updates-3249517
  • issue/automatic_updates-3249983
  • issue/automatic_updates-3249135
  • issue/automatic_updates-3250136
  • issue/automatic_updates-3250386
  • issue/automatic_updates-3251701
  • issue/automatic_updates-3250696
  • issue/automatic_updates-3248911
  • issue/automatic_updates-3227420
  • issue/automatic_updates-3252071
  • issue/automatic_updates-3252097
  • issue/automatic_updates-3252109
  • issue/automatic_updates-3252126
  • issue/automatic_updates-3249130
  • issue/automatic_updates-3251972
  • issue/automatic_updates-3252187
  • issue/automatic_updates-3252328
  • issue/automatic_updates-3252324
  • issue/automatic_updates-3252533
  • issue/automatic_updates-3253055
  • issue/automatic_updates-3253186
  • issue/automatic_updates-3253395
  • issue/automatic_updates-3253400
  • issue/automatic_updates-3253624
  • issue/automatic_updates-3253647
  • issue/automatic_updates-3253649
  • issue/automatic_updates-3253858
  • issue/automatic_updates-3254166
  • issue/automatic_updates-3254207
  • issue/automatic_updates-3279108
  • issue/automatic_updates-3254606
  • issue/automatic_updates-3254616
  • issue/automatic_updates-3254911
  • issue/automatic_updates-3255011
  • issue/automatic_updates-3255014
  • issue/automatic_updates-3255320
  • issue/automatic_updates-3277562
  • issue/automatic_updates-3255678
  • issue/automatic_updates-3256958
  • issue/automatic_updates-3257115
  • issue/automatic_updates-3257432
  • issue/automatic_updates-3257446
  • issue/automatic_updates-3257473
  • issue/automatic_updates-3257134
  • issue/automatic_updates-3257849
  • issue/automatic_updates-3258065
  • issue/automatic_updates-3258056
  • issue/automatic_updates-3258048
  • issue/automatic_updates-3258045
  • issue/automatic_updates-3258464
  • issue/automatic_updates-3258611
  • issue/automatic_updates-3258646
  • issue/automatic_updates-3258661
  • issue/automatic_updates-3258667
  • issue/automatic_updates-3258590
  • issue/automatic_updates-3259228
  • issue/automatic_updates-3259656
  • issue/automatic_updates-3252299
  • issue/automatic_updates-3259664
  • issue/automatic_updates-3259822
  • issue/automatic_updates-3259810
  • issue/automatic_updates-3259814
  • issue/automatic_updates-3260368
  • issue/automatic_updates-3257845
  • issue/automatic_updates-3260664
  • issue/automatic_updates-3260672
  • issue/automatic_updates-3260698
  • issue/automatic_updates-3260662
  • issue/automatic_updates-3260669
  • issue/automatic_updates-3260668
  • issue/automatic_updates-3261637
  • issue/automatic_updates-3261772
  • issue/automatic_updates-3261847
  • issue/automatic_updates-3262016
  • issue/automatic_updates-3262244
  • issue/automatic_updates-3262303
  • issue/automatic_updates-3261642
  • issue/automatic_updates-3262359
  • issue/automatic_updates-3262542
  • issue/automatic_updates-3261098
  • issue/automatic_updates-3260666
  • issue/automatic_updates-3262587
  • issue/automatic_updates-3262965
  • issue/automatic_updates-3263155
  • issue/automatic_updates-3263223
  • issue/automatic_updates-3254755
  • issue/automatic_updates-3261758
  • issue/automatic_updates-3258059
  • issue/automatic_updates-3259196
  • issue/automatic_updates-3263865
  • issue/automatic_updates-3262284
  • issue/automatic_updates-3264554
  • issue/automatic_updates-3248928
  • issue/automatic_updates-3248929
  • issue/automatic_updates-3265072
  • issue/automatic_updates-3265057
  • issue/automatic_updates-3265873
  • issue/automatic_updates-3266092
  • issue/automatic_updates-3266633
  • issue/automatic_updates-3266640
  • issue/automatic_updates-3266687
  • issue/automatic_updates-3266981
  • issue/automatic_updates-3267387
  • issue/automatic_updates-3267389
  • issue/automatic_updates-3267411
  • issue/automatic_updates-3267603
  • issue/automatic_updates-3265874
  • issue/automatic_updates-3267577
  • issue/automatic_updates-3267386
  • issue/automatic_updates-3268363
  • issue/automatic_updates-3268868
  • issue/automatic_updates-3268612
  • issue/automatic_updates-3269097
  • issue/automatic_updates-3267632
  • issue/automatic_updates-3270736
  • issue/automatic_updates-3271144
  • issue/automatic_updates-3271226
  • issue/automatic_updates-3271078
  • issue/automatic_updates-3271371
  • issue/automatic_updates-3267646
  • issue/automatic_updates-3272060
  • issue/automatic_updates-3265031
  • issue/automatic_updates-3253591
  • issue/automatic_updates-3272520
  • issue/automatic_updates-3272061
  • issue/automatic_updates-3272785
  • issue/automatic_updates-3273011
  • issue/automatic_updates-3273008
  • issue/automatic_updates-3273364
  • issue/automatic_updates-3273407
  • issue/automatic_updates-3271235
  • issue/automatic_updates-3273006
  • issue/automatic_updates-3271240
  • issue/automatic_updates-3271468
  • issue/automatic_updates-3272326
  • issue/automatic_updates-3273693
  • issue/automatic_updates-3264849
  • issue/automatic_updates-3273807
  • issue/automatic_updates-3273017
  • issue/automatic_updates-3274269
  • issue/automatic_updates-3274273
  • issue/automatic_updates-3274292
  • issue/automatic_updates-3273812
  • issue/automatic_updates-3274323
  • issue/automatic_updates-3274633
  • issue/automatic_updates-3274858
  • issue/automatic_updates-3274830
  • issue/automatic_updates-3274892
  • issue/automatic_updates-3275075
  • issue/automatic_updates-3275256
  • issue/automatic_updates-3275282
  • issue/automatic_updates-3275320
  • issue/automatic_updates-3275323
  • issue/automatic_updates-3275324
  • issue/automatic_updates-3275317
  • issue/automatic_updates-3275313
  • issue/automatic_updates-3275357
  • issue/automatic_updates-3275474
  • issue/automatic_updates-3275311
  • issue/automatic_updates-3275546
  • issue/automatic_updates-3275508
  • issue/automatic_updates-3275810
  • issue/automatic_updates-3275860
  • issue/automatic_updates-3275865
  • issue/automatic_updates-3275886
  • issue/automatic_updates-3275887
  • issue/automatic_updates-3276031
  • issue/automatic_updates-3276041
  • issue/automatic_updates-3276072
  • issue/automatic_updates-3276159
  • issue/automatic_updates-3276255
  • issue/automatic_updates-3275825
  • issue/automatic_updates-3276661
  • issue/automatic_updates-3275369
  • issue/automatic_updates-3277014
  • issue/automatic_updates-3277035
  • issue/automatic_updates-3272813
  • issue/automatic_updates-3277211
  • issue/automatic_updates-3277229
  • issue/automatic_updates-3275316
  • issue/automatic_updates-3274047
  • issue/automatic_updates-3277815
  • issue/automatic_updates-3276662
  • issue/automatic_updates-3277235
  • issue/automatic_updates-3278411
  • issue/automatic_updates-3278435
  • issue/automatic_updates-3279229
  • issue/automatic_updates-3277007
  • issue/automatic_updates-3284346
  • issue/automatic_updates-3239759
  • issue/automatic_updates-3284495
  • issue/automatic_updates-3284530
  • issue/automatic_updates-3282677
  • issue/automatic_updates-3281379
  • issue/automatic_updates-3285408
  • issue/automatic_updates-3285631
  • issue/automatic_updates-3285669
  • issue/automatic_updates-3273014
  • issue/automatic_updates-3273369
  • issue/automatic_updates-3285491
  • issue/automatic_updates-3285898
  • issue/automatic_updates-3287251
  • issue/automatic_updates-3291147
  • issue/automatic_updates-3286650
  • issue/automatic_updates-3291770
  • issue/automatic_updates-3280403
  • issue/automatic_updates-3291959
  • issue/automatic_updates-3287398
  • issue/automatic_updates-3285145
  • issue/automatic_updates-3292027
  • issue/automatic_updates-3278445
  • issue/automatic_updates-3292933
  • issue/automatic_updates-3292958
  • issue/automatic_updates-3293157
  • issue/automatic_updates-3292956
  • issue/automatic_updates-3293146
  • issue/automatic_updates-3293381
  • issue/automatic_updates-3293449
  • issue/automatic_updates-3293427
  • issue/automatic_updates-3293422
  • issue/automatic_updates-3293685
  • issue/automatic_updates-3291730
  • issue/automatic_updates-3293866
  • issue/automatic_updates-3294338
  • issue/automatic_updates-3293656
  • issue/automatic_updates-3294600
  • issue/automatic_updates-3294335
  • issue/automatic_updates-3295013
  • issue/automatic_updates-3284936
  • issue/automatic_updates-3295596
  • issue/automatic_updates-3295758
  • issue/automatic_updates-3295791
  • issue/automatic_updates-3295830
  • issue/automatic_updates-3295874
  • issue/automatic_updates-3295897
  • issue/automatic_updates-3296074
  • issue/automatic_updates-3295965
  • issue/automatic_updates-3296181
  • issue/automatic_updates-3296065
  • issue/automatic_updates-3296178
  • issue/automatic_updates-3296261
  • issue/automatic_updates-3293148
  • issue/automatic_updates-3303953
  • issue/automatic_updates-3304367
  • issue/automatic_updates-3304640
  • issue/automatic_updates-3304836
  • issue/automatic_updates-3304142
  • issue/automatic_updates-3298349
  • issue/automatic_updates-3298444
  • issue/automatic_updates-3298510
  • issue/automatic_updates-3298431
  • issue/automatic_updates-3298863
  • issue/automatic_updates-3298877
  • issue/automatic_updates-3298904
  • issue/automatic_updates-3298951
  • issue/automatic_updates-3299101
  • issue/automatic_updates-3299417
  • issue/automatic_updates-3293417
  • issue/automatic_updates-3299612
  • issue/automatic_updates-3299093
  • issue/automatic_updates-3299087
  • issue/automatic_updates-3300006
  • issue/automatic_updates-3300036
  • issue/automatic_updates-3293150
  • issue/automatic_updates-3303807
  • issue/automatic_updates-3303929
  • issue/automatic_updates-3304417
  • issue/automatic_updates-3303727
  • issue/automatic_updates-3305527
  • issue/automatic_updates-3301844
  • issue/automatic_updates-3302527
  • issue/automatic_updates-3302673
  • issue/automatic_updates-3302897
  • issue/automatic_updates-3303143
  • issue/automatic_updates-3303168
  • issue/automatic_updates-3303174
  • issue/automatic_updates-3303185
  • issue/automatic_updates-3303200
  • issue/automatic_updates-3303113
  • issue/automatic_updates-3304036
  • issue/automatic_updates-3304165
  • issue/automatic_updates-3304583
  • issue/automatic_updates-3303902
  • issue/automatic_updates-3304651
  • issue/automatic_updates-3305312
  • issue/automatic_updates-3305612
  • issue/automatic_updates-3305568
  • issue/automatic_updates-3305773
  • issue/automatic_updates-3305874
  • issue/automatic_updates-3310901
  • issue/automatic_updates-3310929
  • issue/automatic_updates-3310936
  • issue/automatic_updates-3310972
  • issue/automatic_updates-3311001
  • issue/automatic_updates-3311020
  • issue/automatic_updates-3305240
  • issue/automatic_updates-3305994
  • issue/automatic_updates-3305564
  • issue/automatic_updates-3305998
  • issue/automatic_updates-3306600
  • issue/automatic_updates-3306631
  • issue/automatic_updates-3307086
  • issue/automatic_updates-3307103
  • issue/automatic_updates-3307168
  • issue/automatic_updates-3306163
  • issue/automatic_updates-3304617
  • issue/automatic_updates-3307163
  • issue/automatic_updates-3307398
  • issue/automatic_updates-3307478
  • issue/automatic_updates-3307369
  • issue/automatic_updates-3308404
  • issue/automatic_updates-3307611
  • issue/automatic_updates-3308372
  • issue/automatic_updates-3308686
  • issue/automatic_updates-3308886
  • issue/automatic_updates-3309220
  • issue/automatic_updates-3309270
  • issue/automatic_updates-3308711
  • issue/automatic_updates-3309486
  • issue/automatic_updates-3305167
  • issue/automatic_updates-3309676
  • issue/automatic_updates-3309025
  • issue/automatic_updates-3309891
  • issue/automatic_updates-3308365
  • issue/automatic_updates-3310000
  • issue/automatic_updates-3309205
  • issue/automatic_updates-3248975
  • issue/automatic_updates-3310702
  • issue/automatic_updates-3272313
  • issue/automatic_updates-3310990
  • issue/automatic_updates-3310997
  • issue/automatic_updates-3311200
  • issue/automatic_updates-3310696
  • issue/automatic_updates-3311265
  • issue/automatic_updates-3303167
  • issue/automatic_updates-3310946
  • issue/automatic_updates-3308828
  • issue/automatic_updates-3310666
  • issue/automatic_updates-3109082
  • issue/automatic_updates-3311534
  • issue/automatic_updates-3311436
  • issue/automatic_updates-3308843
  • issue/automatic_updates-3303900
  • issue/automatic_updates-3312085
  • issue/automatic_updates-3312420
  • issue/automatic_updates-3312373
  • issue/automatic_updates-3312421
  • issue/automatic_updates-3312619
  • issue/automatic_updates-3312779
  • issue/automatic_updates-3275991
  • issue/automatic_updates-3312938
  • issue/automatic_updates-3312937
  • issue/automatic_updates-3312960
  • issue/automatic_updates-3312669
  • issue/automatic_updates-3312981
  • issue/automatic_updates-3313319
  • issue/automatic_updates-3313346
  • issue/automatic_updates-3310914
  • issue/automatic_updates-3317220
  • issue/automatic_updates-3317232
  • issue/automatic_updates-3317278
  • issue/automatic_updates-3317409
  • issue/automatic_updates-3317267
  • issue/automatic_updates-3317599
  • issue/automatic_updates-3317988
  • issue/automatic_updates-3318313
  • issue/automatic_updates-3313630
  • issue/automatic_updates-3313717
  • issue/automatic_updates-3313947
  • issue/automatic_updates-3313507
  • issue/automatic_updates-3276645
  • issue/automatic_updates-3313349
  • issue/automatic_updates-3314137
  • issue/automatic_updates-3314143
  • issue/automatic_updates-3304365
  • issue/automatic_updates-3317796
  • issue/automatic_updates-3317996
  • issue/automatic_updates-3316484
  • issue/automatic_updates-3313414
  • issue/automatic_updates-3314764
  • issue/automatic_updates-3314771
  • issue/automatic_updates-3314787
  • issue/automatic_updates-3314805
  • issue/automatic_updates-3314734
  • issue/automatic_updates-3298889
  • issue/automatic_updates-3314803
  • issue/automatic_updates-3315139
  • issue/automatic_updates-3314946
  • issue/automatic_updates-3315449
  • issue/automatic_updates-3315798
  • issue/automatic_updates-3315834
  • issue/automatic_updates-3309602
  • issue/automatic_updates-3316115
  • issue/automatic_updates-3316131
  • issue/automatic_updates-3316293
  • issue/automatic_updates-3316318
  • issue/automatic_updates-3310729
  • issue/automatic_updates-3315700
  • issue/automatic_updates-3316668
  • issue/automatic_updates-3316721
  • issue/automatic_updates-3306283
  • issue/automatic_updates-3316611
  • issue/automatic_updates-3316895
  • issue/automatic_updates-3317385
  • issue/automatic_updates-3318625
  • issue/automatic_updates-3318770
  • issue/automatic_updates-3318846
  • issue/automatic_updates-3318927
  • issue/automatic_updates-3318933
  • issue/automatic_updates-3319044
  • issue/automatic_updates-3319045
  • issue/automatic_updates-3325716
  • issue/automatic_updates-3324421
  • issue/automatic_updates-3320486
  • issue/automatic_updates-3320558
  • issue/automatic_updates-3321206
  • issue/automatic_updates-3326934
  • issue/automatic_updates-3320755
  • issue/automatic_updates-3328765
  • issue/automatic_updates-3325654
  • issue/automatic_updates-3325869
  • issue/automatic_updates-3277034
  • issue/automatic_updates-3328516
  • issue/automatic_updates-3322546
  • issue/automatic_updates-3320487
  • issue/automatic_updates-3320792
  • issue/automatic_updates-3320815
  • issue/automatic_updates-3320638
  • issue/automatic_updates-3321256
  • issue/automatic_updates-3321684
  • issue/automatic_updates-3325522
  • issue/automatic_updates-3326334
  • issue/automatic_updates-3328234
  • issue/automatic_updates-3328740
  • issue/automatic_updates-3316932
  • issue/automatic_updates-3321386
  • issue/automatic_updates-3321933
  • issue/automatic_updates-3321282
  • issue/automatic_updates-3326801
  • issue/automatic_updates-3327753
  • issue/automatic_updates-3328742
  • issue/automatic_updates-3322313
  • issue/automatic_updates-3322203
  • issue/automatic_updates-3322150
  • issue/automatic_updates-3322404
  • issue/automatic_updates-3321236
  • issue/automatic_updates-3321994
  • issue/automatic_updates-3322589
  • issue/automatic_updates-3321904
  • issue/automatic_updates-3316855
  • issue/automatic_updates-3322931
  • issue/automatic_updates-3322913
  • issue/automatic_updates-3323037
  • issue/automatic_updates-3322918
  • issue/automatic_updates-3323211
  • issue/automatic_updates-3323565
  • issue/automatic_updates-3320824
  • issue/automatic_updates-3320836
  • issue/automatic_updates-3329002
  • issue/automatic_updates-3321971
  • issue/automatic_updates-3299094
  • issue/automatic_updates-3248544
  • issue/automatic_updates-3330139
  • issue/automatic_updates-3330365
  • issue/automatic_updates-3330712
  • issue/automatic_updates-3318065
  • issue/automatic_updates-3331310
  • issue/automatic_updates-3322917
  • issue/automatic_updates-3330140
  • issue/automatic_updates-3323003
  • issue/automatic_updates-3331355
  • issue/automatic_updates-3334054
  • issue/automatic_updates-3323706
  • issue/automatic_updates-3331168
  • issue/automatic_updates-3343430
  • issue/automatic_updates-3344562
  • issue/automatic_updates-3345039
  • issue/automatic_updates-3344039
  • issue/automatic_updates-3345313
  • issue/automatic_updates-3331471
  • issue/automatic_updates-3334994
  • issue/automatic_updates-3327229
  • issue/automatic_updates-3343889
  • issue/automatic_updates-3344124
  • issue/automatic_updates-3344689
  • issue/automatic_updates-3316368
  • issue/automatic_updates-3345767
  • issue/automatic_updates-3317815
  • issue/automatic_updates-3328600
  • issue/automatic_updates-3332256
  • issue/automatic_updates-3335766
  • issue/automatic_updates-3335802
  • issue/automatic_updates-3335908
  • issue/automatic_updates-3336243
  • issue/automatic_updates-3336247
  • issue/automatic_updates-3336255
  • issue/automatic_updates-3336259
  • issue/automatic_updates-3337062
  • issue/automatic_updates-3337068
  • issue/automatic_updates-3311229
  • issue/automatic_updates-3337697
  • issue/automatic_updates-3343768
  • issue/automatic_updates-3344127
  • issue/automatic_updates-3344595
  • issue/automatic_updates-3345763
  • issue/automatic_updates-3345765
  • issue/automatic_updates-3345771
  • issue/automatic_updates-3337760
  • issue/automatic_updates-3337049
  • issue/automatic_updates-3342430
  • issue/automatic_updates-3319507
  • issue/automatic_updates-3344583
  • issue/automatic_updates-3345764
  • issue/automatic_updates-3345768
  • issue/automatic_updates-3338667
  • issue/automatic_updates-3339016
  • issue/automatic_updates-3343827
  • issue/automatic_updates-3344556
  • issue/automatic_updates-3338666
  • issue/automatic_updates-3345649
  • issue/automatic_updates-3339657
  • issue/automatic_updates-3339719
  • issue/automatic_updates-3338789
  • issue/automatic_updates-3340022
  • issue/automatic_updates-3340284
  • issue/automatic_updates-3340638
  • issue/automatic_updates-3316617
  • issue/automatic_updates-3341224
  • issue/automatic_updates-3337953
  • issue/automatic_updates-3339714
  • issue/automatic_updates-3341708
  • issue/automatic_updates-3341841
  • issue/automatic_updates-3326486
  • issue/automatic_updates-3321474
  • issue/automatic_updates-3341974
  • issue/automatic_updates-3342120
  • issue/automatic_updates-3342227
  • issue/automatic_updates-3323461
  • issue/automatic_updates-3342137
  • issue/automatic_updates-3342460
  • issue/automatic_updates-3342364
  • issue/automatic_updates-3345028
  • issue/automatic_updates-3345549
  • issue/automatic_updates-3345881
  • issue/automatic_updates-3345762
  • issue/automatic_updates-3342726
  • issue/automatic_updates-3337667
  • issue/automatic_updates-3343463
  • issue/automatic_updates-3345766
  • issue/automatic_updates-3345754
  • issue/automatic_updates-3345633
  • issue/automatic_updates-3345772
  • issue/automatic_updates-3345769
  • issue/automatic_updates-3345761
  • issue/automatic_updates-3345755
  • issue/automatic_updates-3345760
  • issue/automatic_updates-3345757
  • issue/automatic_updates-3346520
  • issue/automatic_updates-3346545
  • issue/automatic_updates-3337054
  • issue/automatic_updates-3346628
  • issue/automatic_updates-3346717
  • issue/automatic_updates-3346594
  • issue/automatic_updates-3346659
  • issue/automatic_updates-3347031
  • issue/automatic_updates-3346547
  • issue/automatic_updates-3347164
  • issue/automatic_updates-3318306
  • issue/automatic_updates-3345646
  • issue/automatic_updates-3347165
  • issue/automatic_updates-3347959
  • issue/automatic_updates-3347267
  • issue/automatic_updates-3338346
  • issue/automatic_updates-3348122
  • issue/automatic_updates-3348129
  • issue/automatic_updates-3348162
  • issue/automatic_updates-3348276
  • issue/automatic_updates-3348441
  • issue/automatic_updates-3351604
  • issue/automatic_updates-3316843
  • issue/automatic_updates-3351908
  • issue/automatic_updates-3352731
  • issue/automatic_updates-3352898
  • issue/automatic_updates-3348866
  • issue/automatic_updates-3342817
  • issue/automatic_updates-3348159
  • issue/automatic_updates-3349142
  • issue/automatic_updates-3349966
  • issue/automatic_updates-3350909
  • issue/automatic_updates-3351594
  • issue/automatic_updates-3351883
  • issue/automatic_updates-3351925
  • issue/automatic_updates-3352198
  • issue/automatic_updates-3334552
  • issue/automatic_updates-3342790
  • issue/automatic_updates-3345222
  • issue/automatic_updates-3351212
  • issue/automatic_updates-3351093
  • issue/automatic_updates-3351247
  • issue/automatic_updates-3351962
  • issue/automatic_updates-3345641
  • issue/automatic_updates-3338940
  • issue/automatic_updates-3343721
  • issue/automatic_updates-3351069
  • issue/automatic_updates-3353219
  • issue/automatic_updates-3159920
  • issue/automatic_updates-3352355
  • issue/automatic_updates-3341469
  • issue/automatic_updates-3354099
  • issue/automatic_updates-3339659
  • issue/automatic_updates-3354312
  • issue/automatic_updates-3351895
  • issue/automatic_updates-3354249
  • issue/automatic_updates-3353270
  • issue/automatic_updates-3354003
  • issue/automatic_updates-3355074
  • issue/automatic_updates-3355094
  • issue/automatic_updates-3355105
  • issue/automatic_updates-3355162
  • issue/automatic_updates-3355446
  • issue/automatic_updates-3355045
  • issue/automatic_updates-3355558
  • issue/automatic_updates-3355553
  • issue/automatic_updates-3354594
  • issue/automatic_updates-3355609
  • issue/automatic_updates-3354325
  • issue/automatic_updates-3356395
  • issue/automatic_updates-3356638
  • issue/automatic_updates-3356640
  • issue/automatic_updates-3354701
  • issue/automatic_updates-3355463
  • issue/automatic_updates-3356804
  • issue/automatic_updates-3357721
  • issue/automatic_updates-3357578
  • issue/automatic_updates-3357657
  • issue/automatic_updates-3304108
  • issue/automatic_updates-3357941
  • issue/automatic_updates-3358012
  • issue/automatic_updates-3345535
  • issue/automatic_updates-3354827
  • issue/automatic_updates-3358570
  • issue/automatic_updates-3358878
  • issue/automatic_updates-3355628
  • issue/automatic_updates-3358504
  • issue/automatic_updates-3357969
  • issue/automatic_updates-3359609
  • issue/automatic_updates-3359727
  • issue/automatic_updates-3359825
  • issue/automatic_updates-3359820
  • issue/automatic_updates-3360548
  • issue/automatic_updates-3357480
  • issue/automatic_updates-3360656
  • issue/automatic_updates-3360763
  • issue/automatic_updates-3360655
  • issue/automatic_updates-3355618
  • issue/automatic_updates-3349351
  • issue/automatic_updates-3362110
  • issue/automatic_updates-3362143
  • issue/automatic_updates-3362589
  • issue/automatic_updates-3349004
  • issue/automatic_updates-3362507
  • issue/automatic_updates-3362746
  • issue/automatic_updates-3362978
  • issue/automatic_updates-3363259
  • issue/automatic_updates-3363725
  • issue/automatic_updates-3363926
  • issue/automatic_updates-3363937
  • issue/automatic_updates-3364514
  • issue/automatic_updates-3284443
  • issue/automatic_updates-3363938
  • issue/automatic_updates-3364731
  • issue/automatic_updates-3364748
  • issue/automatic_updates-3364735
  • issue/automatic_updates-3364725
  • issue/automatic_updates-3359670
  • issue/automatic_updates-3365133
  • issue/automatic_updates-3365151
  • issue/automatic_updates-3365177
  • issue/automatic_updates-3364958
  • issue/automatic_updates-3365390
  • issue/automatic_updates-3365414
  • issue/automatic_updates-3346644
  • issue/automatic_updates-3366267
  • issue/automatic_updates-3366289
  • issue/automatic_updates-3366499
  • issue/automatic_updates-3365437
  • issue/automatic_updates-3354914
  • issue/automatic_updates-3253828
  • issue/automatic_updates-3345484
  • issue/automatic_updates-3352846
  • issue/automatic_updates-3368741
  • issue/automatic_updates-3406008
  • issue/automatic_updates-3406122
  • issue/automatic_updates-3370197
  • issue/automatic_updates-3366271
  • issue/automatic_updates-3364135
  • issue/automatic_updates-3370603
  • issue/automatic_updates-3400146
  • issue/automatic_updates-3406010
  • issue/automatic_updates-3404429
  • issue/automatic_updates-3371212
  • issue/automatic_updates-3371076
  • issue/automatic_updates-3372673
  • issue/automatic_updates-3368808
  • issue/automatic_updates-3374175
  • issue/automatic_updates-3374739
  • issue/automatic_updates-3374753
  • issue/automatic_updates-3375679
  • issue/automatic_updates-3377237
  • issue/automatic_updates-3377245
  • issue/automatic_updates-3378774
  • issue/automatic_updates-3378793
  • issue/automatic_updates-3360485
  • issue/automatic_updates-3380698
  • issue/automatic_updates-3375940
  • issue/automatic_updates-3381294
  • issue/automatic_updates-3381484
  • issue/automatic_updates-3382942
  • issue/automatic_updates-3383462
  • issue/automatic_updates-3383451
  • issue/automatic_updates-3384359
  • issue/automatic_updates-3384637
  • issue/automatic_updates-3375640
  • issue/automatic_updates-3386135
  • issue/automatic_updates-3386533
  • issue/automatic_updates-3387610
  • issue/automatic_updates-3387637
  • issue/automatic_updates-3387656
  • issue/automatic_updates-3389157
  • issue/automatic_updates-3388965
  • issue/automatic_updates-3387379
  • issue/automatic_updates-3390493
  • issue/automatic_updates-3308235
  • issue/automatic_updates-3391715
  • issue/automatic_updates-3392246
  • issue/automatic_updates-3393633
  • issue/automatic_updates-3379344
  • issue/automatic_updates-3394413
  • issue/automatic_updates-3394705
  • issue/automatic_updates-3394936
  • issue/automatic_updates-3363497
  • issue/automatic_updates-3395782
  • issue/automatic_updates-3341406
  • issue/automatic_updates-3311472
  • issue/automatic_updates-3397228
  • issue/automatic_updates-3352654
  • issue/automatic_updates-3398782
  • issue/automatic_updates-3399147
  • issue/automatic_updates-3399155
  • issue/automatic_updates-3406812
  • issue/automatic_updates-3408483
  • issue/automatic_updates-3408488
  • issue/automatic_updates-3408560
  • issue/automatic_updates-3437633
  • issue/automatic_updates-3408835
  • issue/automatic_updates-3408937
  • issue/automatic_updates-3409491
  • issue/automatic_updates-3409519
  • issue/automatic_updates-3377458
  • issue/automatic_updates-3437951
  • issue/automatic_updates-3409774
  • issue/automatic_updates-3410047
  • issue/automatic_updates-3411110
  • issue/automatic_updates-3411241
  • issue/automatic_updates-3411276
  • issue/automatic_updates-3411392
  • issue/automatic_updates-3411240
  • issue/automatic_updates-3412630
  • issue/automatic_updates-3413866
  • issue/automatic_updates-3414168
  • issue/automatic_updates-3415291
  • issue/automatic_updates-3415389
  • issue/automatic_updates-3415403
  • issue/automatic_updates-3416768
  • issue/automatic_updates-3417905
  • issue/automatic_updates-3420188
  • issue/automatic_updates-3421641
  • issue/automatic_updates-3424290
  • issue/automatic_updates-3426229
  • issue/automatic_updates-3426666
  • issue/automatic_updates-3426716
  • issue/automatic_updates-3428199
  • issue/automatic_updates-3436741
  • issue/automatic_updates-3441923
  • issue/automatic_updates-3428651
  • issue/automatic_updates-3441799
  • issue/automatic_updates-3443249
  • issue/automatic_updates-3428922
  • issue/automatic_updates-3441817
  • issue/automatic_updates-3429248
  • issue/automatic_updates-3440646
  • issue/automatic_updates-3437877
  • issue/automatic_updates-3445149
  • issue/automatic_updates-3429268
  • issue/automatic_updates-3442153
  • issue/automatic_updates-3438156
  • issue/automatic_updates-3436993
  • issue/automatic_updates-3437704
  • issue/automatic_updates-3432496
  • issue/automatic_updates-3440006
  • issue/automatic_updates-3435893
  • issue/automatic_updates-3441577
  • issue/automatic_updates-3437023
  • issue/automatic_updates-3432391
  • issue/automatic_updates-3432447
  • issue/automatic_updates-3432472
  • issue/automatic_updates-3432489
  • issue/automatic_updates-3432476
  • issue/automatic_updates-3435918
  • issue/automatic_updates-3439067
  • issue/automatic_updates-3437409
  • issue/automatic_updates-3449093
  • issue/automatic_updates-3449480
  • issue/automatic_updates-3449519
  • issue/automatic_updates-3449631
  • issue/automatic_updates-3449636
  • issue/automatic_updates-3449689
  • issue/automatic_updates-3449693
  • issue/automatic_updates-3450884
  • issue/automatic_updates-3452870
  • issue/automatic_updates-3453030
  • issue/automatic_updates-3455161
  • issue/automatic_updates-3459557
  • issue/automatic_updates-3462138
  • issue/automatic_updates-3462168
  • issue/automatic_updates-3462883
  • issue/automatic_updates-3463662
  • issue/automatic_updates-3463813
  • issue/automatic_updates-3446371
  • issue/automatic_updates-3465155
  • issue/automatic_updates-3340355
  • issue/automatic_updates-3467749
  • issue/automatic_updates-3473410
  • issue/automatic_updates-3441926
  • issue/automatic_updates-3474603
  • issue/automatic_updates-3484802
  • issue/automatic_updates-3498586
  • issue/automatic_updates-3499481
  • issue/automatic_updates-3498018
  • issue/automatic_updates-3506632
  • issue/automatic_updates-3511959
  • issue/automatic_updates-3511943
981 results
Show changes
Showing
with 341 additions and 151 deletions
......@@ -4,6 +4,7 @@ declare(strict_types = 1);
namespace Drupal\package_manager;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface;
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
......@@ -48,18 +49,24 @@ final class PackageManagerUpdateProcessor extends UpdateProcessor {
* The key/value factory.
* @param \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface $key_value_expirable_factory
* The expirable key/value factory.
* @param \Drupal\Component\Datetime\TimeInterface $time
* The time service.
*/
public function __construct(ConfigFactoryInterface $config_factory, QueueFactory $queue_factory, UpdateFetcherInterface $update_fetcher, StateInterface $state_store, PrivateKey $private_key, KeyValueFactoryInterface $key_value_factory, KeyValueExpirableFactoryInterface $key_value_expirable_factory) {
$this->updateFetcher = $update_fetcher;
$this->updateSettings = $config_factory->get('update.settings');
public function __construct(
ConfigFactoryInterface $config_factory,
QueueFactory $queue_factory,
UpdateFetcherInterface $update_fetcher,
StateInterface $state_store,
PrivateKey $private_key,
KeyValueFactoryInterface $key_value_factory,
KeyValueExpirableFactoryInterface $key_value_expirable_factory,
TimeInterface $time,
) {
parent::__construct(...func_get_args());
$this->fetchQueue = $queue_factory->get('package_manager.update_fetch_tasks');
$this->tempStore = $key_value_expirable_factory->get('package_manager.update');
$this->fetchTaskStore = $key_value_factory->get('package_manager.update_fetch_task');
$this->availableReleasesTempStore = $key_value_expirable_factory->get('package_manager.update_available_releases');
$this->stateStore = $state_store;
$this->privateKey = $private_key;
$this->fetchTasks = [];
$this->failed = [];
}
/**
......
......@@ -67,7 +67,7 @@ class SiteConfigurationExcluder implements EventSubscriberInterface {
}
/**
* Makes the staged `sites/default` directory world-writable.
* Makes the staged `sites/default` directory owner-writable.
*
* This is done to allow the core scaffold plugin to make changes in
* `sites/default`, if necessary, without breaking if `sites/default` is not
......@@ -89,7 +89,7 @@ class SiteConfigurationExcluder implements EventSubscriberInterface {
if (!is_dir($dir)) {
return;
}
if (!$this->fileSystem->chmod($dir, 0777)) {
if (!$this->fileSystem->chmod($dir, 0700)) {
throw new FileException("Could not change permissions on '$dir'.");
}
}
......
......@@ -59,7 +59,9 @@ final class SiteFilesExcluder implements EventSubscriberInterface {
$path = $wrapper->getDirectoryPath();
if ($this->fileSystem->isAbsolutePath($path)) {
$event->addPathsRelativeToProjectRoot([realpath($path)]);
if ($path = realpath($path)) {
$event->addPathsRelativeToProjectRoot([$path]);
}
}
else {
$event->addPathsRelativeToWebRoot([$path]);
......
......@@ -6,7 +6,7 @@ namespace Drupal\package_manager\PathExcluder;
use Drupal\Core\Database\Connection;
use Drupal\package_manager\Event\CollectPathsToExcludeEvent;
use Drupal\package_manager\PathLocator;
use PhpTuf\ComposerStager\API\Path\Factory\PathFactoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
......@@ -22,16 +22,14 @@ class SqliteDatabaseExcluder implements EventSubscriberInterface {
/**
* Constructs a SqliteDatabaseExcluder object.
*
* @param \Drupal\package_manager\PathLocator $pathLocator
* The path locator service.
* @param \PhpTuf\ComposerStager\API\Path\Factory\PathFactoryInterface $pathFactory
* The path factory service.
* @param \Drupal\Core\Database\Connection $database
* The database connection.
*/
public function __construct(
private readonly PathLocator $pathLocator,
// TRICKY: this cannot be private nor readonly for testing purposes.
// @see \Drupal\Tests\package_manager\Kernel\PathExcluder\SqliteDatabaseExcluderTest::mockDatabase()
protected Connection $database
private readonly PathFactoryInterface $pathFactory,
private readonly Connection $database,
) {}
/**
......@@ -50,19 +48,27 @@ class SqliteDatabaseExcluder implements EventSubscriberInterface {
* The event object.
*/
public function excludeDatabaseFiles(CollectPathsToExcludeEvent $event): void {
// If the database is SQLite, it might be located in the active directory
// and we should exclude it. Always treat it as relative to the project root.
// If the database is SQLite, it might be located in the project directory
// and we should exclude it.
if ($this->database->driver() === 'sqlite') {
$options = $this->database->getConnectionOptions();
// Nothing to exclude if the database lives outside the project root.
if (str_starts_with($options['database'], '/') && !str_starts_with($options['database'], $this->pathLocator->getProjectRoot())) {
return;
$db_path = $this->database->getConnectionOptions()['database'];
// Exclude the database file and auxiliary files created by SQLite.
$paths = [$db_path, "$db_path-shm", "$db_path-wal"];
// If the database path is absolute, it might be outside the project root,
// in which case we don't need to do anything.
if ($this->pathFactory->create($db_path)->isAbsolute()) {
try {
$event->addPathsRelativeToProjectRoot($paths);
}
catch (\LogicException) {
// The database is outside of the project root, so we're done.
}
}
else {
// The database is in the web root, and must be excluded relative to it.
$event->addPathsRelativeToWebRoot($paths);
}
$event->addPathsRelativeToProjectRoot([
$options['database'],
$options['database'] . '-shm',
$options['database'] . '-wal',
]);
}
}
......
......@@ -5,9 +5,15 @@ declare(strict_types = 1);
namespace Drupal\package_manager\PathExcluder;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\package_manager\ComposerInspector;
use Drupal\package_manager\Event\CollectPathsToExcludeEvent;
use Drupal\package_manager\Event\StatusCheckEvent;
use Drupal\package_manager\PathLocator;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\NullLogger;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
......@@ -23,12 +29,22 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
*
* If web root and project root are the same, nothing is excluded.
*
* This excluder can be disabled by changing the config setting
* `package_manager.settings:include_unknown_files_in_project_root` to TRUE.
* This may be needed for sites that have files outside the web root (besides
* the vendor directory) which are nonetheless needed in order for Composer to
* assemble the code base correctly; a classic example would be a directory of
* patch files used by `cweagans/composer-patches`.
*
* @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 {
final class UnknownPathExcluder implements EventSubscriberInterface, LoggerAwareInterface {
use LoggerAwareTrait;
use StringTranslationTrait;
/**
* Constructs a UnknownPathExcluder object.
......@@ -37,11 +53,16 @@ final class UnknownPathExcluder implements EventSubscriberInterface {
* The Composer inspector service.
* @param \Drupal\package_manager\PathLocator $pathLocator
* The path locator service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
* The config factory service.
*/
public function __construct(
private readonly ComposerInspector $composerInspector,
private readonly PathLocator $pathLocator,
) {}
private readonly ConfigFactoryInterface $configFactory,
) {
$this->setLogger(new NullLogger());
}
/**
* {@inheritdoc}
......@@ -49,53 +70,110 @@ final class UnknownPathExcluder implements EventSubscriberInterface {
public static function getSubscribedEvents(): array {
return [
CollectPathsToExcludeEvent::class => 'excludeUnknownPaths',
StatusCheckEvent::class => 'logExcludedPaths',
];
}
/**
* Excludes unknown paths from stage operations.
* Returns the paths to exclude from stage operations.
*
* @param \Drupal\package_manager\Event\CollectPathsToExcludeEvent $event
* The event object.
* @return string[]
* The paths that should be excluded from stage operations, relative to the
* project root.
*
* @throws \Exception
* See \Drupal\package_manager\ComposerInspector::validate().
*/
public function excludeUnknownPaths(CollectPathsToExcludeEvent $event): void {
$project_root = $this->pathLocator->getProjectRoot();
$web_root = $project_root . DIRECTORY_SEPARATOR . $this->pathLocator->getWebRoot();
if (realpath($web_root) === $project_root) {
return;
private function getExcludedPaths(): array {
// If this excluder is disabled, or the project root and web root are the
// same, we are not excluding any paths.
$is_disabled = $this->configFactory->get('package_manager.settings')
->get('include_unknown_files_in_project_root');
$web_root = $this->pathLocator->getWebRoot();
if ($is_disabled || empty($web_root)) {
return [];
}
// To determine the scaffold files to exclude, the installed packages must
// be known, and that requires Composer commands to be able to run. This
// intentionally does not catch exceptions: failed Composer validation in
// the project root implies that this excluder cannot function correctly.
// Note: the call to ComposerInspector::getInstalledPackagesList() would
// To determine the files to include, the installed packages must be known,
// and that requires Composer commands to be able to run. This intentionally
// does not catch exceptions: failed Composer validation in the project root
// implies that this excluder cannot function correctly.
// Note: the call to ComposerInspector::getConfig() would
// also have triggered this, but explicitness is preferred here.
// @see \Drupal\package_manager\StatusCheckTrait::runStatusCheck()
$project_root = $this->pathLocator->getProjectRoot();
$this->composerInspector->validate($project_root);
$vendor_dir = $this->pathLocator->getVendorDirectory();
$scaffold_files_paths = $this->getScaffoldFiles();
// Search for all files (including hidden ones) in project root.
$paths_in_project_root = glob("$project_root/{,.}*", GLOB_BRACE);
$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;
// The vendor directory and web root are always included in staging
// operations, along with `composer.json`, `composer.lock`, and any scaffold
// files provided by Drupal core.
$always_include = [
$this->composerInspector->getConfig('vendor-dir', $project_root),
$web_root,
'composer.json',
'composer.lock',
];
foreach ($this->getScaffoldFiles() as $scaffold_file_path) {
// The web root is always included in staging operations, so we don't need
// to do anything special for scaffold files that live in it.
if (str_starts_with($scaffold_file_path, '[web-root]')) {
continue;
}
$always_include[] = ltrim($scaffold_file_path, '/');
}
// Search for all files (including hidden ones) in the project root. We need
// to use readdir() and friends here, rather than glob(), since certain
// glob() flags aren't supported on all systems. We also can't use
// \Drupal\Core\File\FileSystemInterface::scanDirectory(), because it
// unconditionally ignores hidden files and directories.
$files_in_project_root = [];
$handle = opendir($project_root);
if (empty($handle)) {
throw new \RuntimeException("Could not scan for files in the project root.");
}
while ($entry = readdir($handle)) {
$files_in_project_root[] = $entry;
}
closedir($handle);
return array_diff($files_in_project_root, $always_include, ['.', '..']);
}
/**
* Excludes unknown paths from stage operations.
*
* @param \Drupal\package_manager\Event\CollectPathsToExcludeEvent $event
* The event object.
*/
public function excludeUnknownPaths(CollectPathsToExcludeEvent $event): void {
// We can exclude the paths as-is; they are already relative to the project
// root.
$event->add(...$this->getExcludedPaths());
}
/**
* Logs the paths that will be excluded from stage operations.
*/
public function logExcludedPaths(): void {
$excluded_paths = $this->getExcludedPaths();
if ($excluded_paths) {
sort($excluded_paths);
$message = $this->t("The following paths in @project_root aren't recognized as part of your Drupal site, so to be safe, Package Manager is excluding them from all stage operations. If these files are not needed for Composer to work properly in your site, no action is needed. Otherwise, you can disable this behavior by setting the <code>package_manager.settings:include_unknown_files_in_project_root</code> config setting to <code>TRUE</code>.\n\n@list", [
'@project_root' => $this->pathLocator->getProjectRoot(),
'@list' => implode("\n", $excluded_paths),
]);
$this->logger->info($message);
}
$event->addPathsRelativeToProjectRoot($paths);
}
/**
* Gets the path of scaffold files, for example 'index.php' and 'robots.txt'.
*
* @return array
* The array of scaffold file paths.
* @return string[]
* The paths of scaffold files provided by `drupal/core`, relative to the
* project root.
*
* @todo Intelligently load scaffold files in https://drupal.org/i/3343802.
*/
......@@ -103,10 +181,9 @@ final class UnknownPathExcluder implements EventSubscriberInterface {
$project_root = $this->pathLocator->getProjectRoot();
$packages = $this->composerInspector->getInstalledPackagesList($project_root);
$extra = Json::decode($this->composerInspector->getConfig('extra', $packages['drupal/core']->path . '/composer.json'));
if (isset($extra['drupal-scaffold']['file-mapping'])) {
return array_keys($extra['drupal-scaffold']['file-mapping']);
}
return [];
$scaffold_files = $extra['drupal-scaffold']['file-mapping'] ?? [];
return str_replace('[project-root]', '', array_keys($scaffold_files));
}
}
<?php
namespace Drupal\package_manager\Plugin\QueueWorker;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Queue\QueueWorkerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Processes a queue of defunct stage directories, deleting them.
*
* @QueueWorker(
* id = "package_manager_cleanup",
* title = @Translation("Stage directory cleaner"),
* cron = {"time" = 30}
* )
*/
final class Cleaner extends QueueWorkerBase implements ContainerFactoryPluginInterface {
/**
* Constructs a new Cleaner instance.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin ID.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\File\FileSystemInterface $fileSystem
* The file system service.
*/
public function __construct(array $configuration, string $plugin_id, mixed $plugin_definition, private readonly FileSystemInterface $fileSystem) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get(FileSystemInterface::class),
);
}
/**
* {@inheritdoc}
*/
public function processItem($dir) {
assert(is_string($dir));
if (file_exists($dir)) {
$this->fileSystem->deleteRecursive($dir, function (string $path): void {
$this->fileSystem->chmod($path, is_dir($path) ? 0700 : 0600);
});
}
}
}
......@@ -7,8 +7,7 @@ namespace Drupal\package_manager;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\File\FileSystemInterface;
use PhpTuf\ComposerStager\API\Process\Factory\ProcessFactoryInterface;
use PhpTuf\ComposerStager\Internal\Process\Factory\ProcessFactory as StagerProcessFactory;
use Symfony\Component\Process\Process;
use PhpTuf\ComposerStager\API\Process\Service\ProcessInterface;
// cspell:ignore BINDIR
......@@ -29,13 +28,13 @@ final class ProcessFactory implements ProcessFactoryInterface {
* The file system service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
* The config factory service.
* @param \PhpTuf\ComposerStager\Internal\Process\Factory\ProcessFactory $decorated
* @param \PhpTuf\ComposerStager\API\Process\Factory\ProcessFactoryInterface $decorated
* The decorated process factory service.
*/
public function __construct(
private readonly FileSystemInterface $fileSystem,
private readonly ConfigFactoryInterface $configFactory,
private readonly StagerProcessFactory $decorated,
private readonly ProcessFactoryInterface $decorated,
) {}
/**
......@@ -57,7 +56,7 @@ final class ProcessFactory implements ProcessFactoryInterface {
/**
* {@inheritdoc}
*/
public function create(array $command): Process {
public function create(array $command): ProcessInterface {
$process = $this->decorated->create($command);
$env = $process->getEnv();
......@@ -81,7 +80,7 @@ final class ProcessFactory implements ProcessFactoryInterface {
* @see php_sapi_name()
* @see https://www.php.net/manual/en/reserved.constants.php
*/
protected static function getPhpDirectory(): string {
private static function getPhpDirectory(): string {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'cli-server') {
return dirname(PHP_BINARY);
}
......
......@@ -4,7 +4,8 @@ declare(strict_types = 1);
namespace Drupal\package_manager;
use PhpTuf\ComposerStager\API\Process\Service\ProcessOutputCallbackInterface;
use PhpTuf\ComposerStager\API\Process\Service\OutputCallbackInterface;
use PhpTuf\ComposerStager\API\Process\Value\OutputTypeEnum;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\NullLogger;
......@@ -19,7 +20,7 @@ use Psr\Log\NullLogger;
* at any time without warning. External code should not interact with this
* class.
*/
final class ProcessOutputCallback implements ProcessOutputCallbackInterface, LoggerAwareInterface {
final class ProcessOutputCallback implements OutputCallbackInterface, LoggerAwareInterface {
use LoggerAwareTrait;
......@@ -47,20 +48,14 @@ final class ProcessOutputCallback implements ProcessOutputCallbackInterface, Log
/**
* {@inheritdoc}
*/
public function __invoke(string $type, string $buffer): void {
// \Symfony\Component\Process\Process defines the output types in lowercase,
// but Composer Stager uses uppercase.
$type = strtoupper($type);
public function __invoke(OutputTypeEnum $type, string $buffer): void {
if ($type === self::OUT) {
if ($type === OutputTypeEnum::OUT) {
$this->outBuffer .= $buffer;
}
elseif ($type === self::ERR) {
elseif ($type === OutputTypeEnum::ERR) {
$this->errorBuffer .= $buffer;
}
else {
throw new \InvalidArgumentException("Unsupported output type: '$type'");
}
}
/**
......
......@@ -192,7 +192,7 @@ final class ProjectInfo {
// update processor service.
if (!isset($available_projects[$this->name])) {
/** @var \Drupal\package_manager\PackageManagerUpdateProcessor $update_processor */
$update_processor = \Drupal::service('package_manager.update_processor');
$update_processor = \Drupal::service(PackageManagerUpdateProcessor::class);
if ($project_data = $update_processor->getProjectData($this->name)) {
$available_projects[$this->name] = $project_data;
}
......
......@@ -6,21 +6,19 @@ namespace Drupal\package_manager;
use Composer\Semver\VersionParser;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Component\Utility\Random;
use Drupal\Core\Queue\QueueFactory;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\TempStore\SharedTempStore;
use Drupal\Core\TempStore\SharedTempStoreFactory;
use Drupal\Core\Utility\Error;
use Drupal\package_manager\Event\CollectPathsToExcludeEvent;
use Drupal\package_manager\Event\PostApplyEvent;
use Drupal\package_manager\Event\PostCreateEvent;
use Drupal\package_manager\Event\PostDestroyEvent;
use Drupal\package_manager\Event\PostRequireEvent;
use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\PreDestroyEvent;
use Drupal\package_manager\Event\PreOperationStageEvent;
use Drupal\package_manager\Event\PreRequireEvent;
use Drupal\package_manager\Event\StageEvent;
......@@ -34,7 +32,7 @@ use PhpTuf\ComposerStager\API\Core\StagerInterface;
use PhpTuf\ComposerStager\API\Exception\InvalidArgumentException;
use PhpTuf\ComposerStager\API\Exception\PreconditionException;
use PhpTuf\ComposerStager\API\Path\Factory\PathFactoryInterface;
use PhpTuf\ComposerStager\API\Path\Value\PathList;
use PhpTuf\ComposerStager\API\Path\Value\PathListInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\NullLogger;
......@@ -161,6 +159,17 @@ abstract class StageBase implements LoggerAwareInterface {
*/
protected SharedTempStore $tempStore;
/**
* The stage type.
*
* To ensure that stage classes do not unintentionally use another stage's
* type, all concrete subclasses MUST explicitly define this property.
* The recommended pattern is `MODULE:TYPE`.
*
* @var string
*/
protected string $type;
/**
* Constructs a new Stage object.
*
......@@ -172,8 +181,8 @@ abstract class StageBase implements LoggerAwareInterface {
* The stager service.
* @param \PhpTuf\ComposerStager\API\Core\CommitterInterface $committer
* The committer service.
* @param \Drupal\Core\File\FileSystemInterface $fileSystem
* The file system service.
* @param \Drupal\Core\Queue\QueueFactory $queueFactory
* The queue factory.
* @param \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $eventDispatcher
* The event dispatcher service.
* @param \Drupal\Core\TempStore\SharedTempStoreFactory $tempStoreFactory
......@@ -190,7 +199,7 @@ abstract class StageBase implements LoggerAwareInterface {
protected readonly BeginnerInterface $beginner,
protected readonly StagerInterface $stager,
protected readonly CommitterInterface $committer,
protected readonly FileSystemInterface $fileSystem,
protected readonly QueueFactory $queueFactory,
protected EventDispatcherInterface $eventDispatcher,
protected readonly SharedTempStoreFactory $tempStoreFactory,
protected readonly TimeInterface $time,
......@@ -201,6 +210,31 @@ abstract class StageBase implements LoggerAwareInterface {
$this->setLogger(new NullLogger());
}
/**
* Gets the stage type.
*
* The stage type can be used by stage event subscribers to implement logic
* specific to certain stages, without relying on the class name (which may
* not be part of module's public API).
*
* @return string
* The stage type.
*
* @throws \LogicException
* Thrown if $this->type is not explicitly overridden.
*/
final public function getType(): string {
$reflector = new \ReflectionProperty($this, 'type');
// The $type property must ALWAYS be overridden. This means that different
// subclasses can return the same value (thus allowing one stage to
// impersonate another one), but if that happens, it is intentional.
if ($reflector->getDeclaringClass()->getName() === static::class) {
return $this->type;
}
throw new \LogicException(static::class . ' must explicitly override the $type property.');
}
/**
* Determines if the stage directory can be created.
*
......@@ -254,7 +288,7 @@ abstract class StageBase implements LoggerAwareInterface {
/**
* Collects paths that Composer Stager should exclude.
*
* @return string[]
* @return \PhpTuf\ComposerStager\API\Path\Value\PathListInterface
* A list of paths that Composer Stager should exclude when creating the
* stage directory and applying staged changes to the active directory.
*
......@@ -264,15 +298,14 @@ abstract class StageBase implements LoggerAwareInterface {
* @see ::create()
* @see ::apply()
*/
protected function getPathsToExclude(): array {
protected function getPathsToExclude(): PathListInterface {
$event = new CollectPathsToExcludeEvent($this, $this->pathLocator, $this->pathFactory);
try {
$this->eventDispatcher->dispatch($event);
return $this->eventDispatcher->dispatch($event);
}
catch (\Throwable $e) {
$this->rethrowAsStageException($e);
}
return $event->getAll();
}
/**
......@@ -311,26 +344,40 @@ abstract class StageBase implements LoggerAwareInterface {
// to create a stage directory at around the same time. If an error occurs
// while the event is being processed, the stage is marked as available.
// @see ::dispatch()
$id = Crypt::randomBytesBase64();
// We specifically generate a random 32-character alphanumeric name in order
// to guarantee that the the stage ID won't start with -, which could cause
// it to be interpreted as an option if it's used as a command-line
// argument. (For example,
// \Drupal\Component\Utility\Crypt::randomBytesBase64() would be vulnerable
// to this; the stage ID needs to be unique, but not cryptographically so.)
$id = (new Random())->name(32);
// Re-acquire the tempstore to ensure that the lock is written by whoever is
// actually logged in (or not) right now, since it's possible that the stage
// was instantiated (i.e., __construct() was called) by a different session,
// which would result in the lock having the wrong owner and the stage not
// being claimable by whoever is actually creating it.
$this->tempStore = $this->tempStoreFactory->get('package_manager_stage');
$this->tempStore->set(static::TEMPSTORE_LOCK_KEY, [$id, static::class]);
// For the lock value, we use both the stage's class and its type in order
// to prevent a stage from being manipulated by two different classes during
// a single life cycle.
$this->tempStore->set(static::TEMPSTORE_LOCK_KEY, [
$id,
static::class,
$this->getType(),
]);
$this->claim($id);
$active_dir = $this->pathFactory->create($this->pathLocator->getProjectRoot());
$stage_dir = $this->pathFactory->create($this->getStageDirectory());
$event = new PreCreateEvent($this, $this->getPathsToExclude());
$excluded_paths = $this->getPathsToExclude();
$event = new PreCreateEvent($this, $excluded_paths);
// If an error occurs and we won't be able to create the stage, mark it as
// available.
$this->dispatch($event, [$this, 'markAsAvailable']);
try {
$this->beginner->begin($active_dir, $stage_dir, new PathList(...$event->getExcludedPaths()), NULL, $timeout);
$this->beginner->begin($active_dir, $stage_dir, $excluded_paths, NULL, $timeout);
}
catch (\Throwable $error) {
$this->destroy();
......@@ -409,7 +456,7 @@ abstract class StageBase implements LoggerAwareInterface {
// If constraints were changed, update those packages.
if ($runtime || $dev) {
$command = array_merge(['update', '--with-all-dependencies'], $runtime, $dev);
$command = array_merge(['update', '--with-all-dependencies', '--optimize-autoloader'], $runtime, $dev);
$do_stage($command);
}
$this->dispatch(new PostRequireEvent($this, $runtime, $dev));
......@@ -442,23 +489,19 @@ abstract class StageBase implements LoggerAwareInterface {
$active_dir = $this->pathFactory->create($this->pathLocator->getProjectRoot());
$stage_dir = $this->pathFactory->create($this->getStageDirectory());
$excluded_paths = $this->getPathsToExclude();
$event = new PreApplyEvent($this, $excluded_paths);
// If an error occurs while dispatching the events, ensure that ::destroy()
// doesn't think we're in the middle of applying the staged changes to the
// active directory.
$event = new PreApplyEvent($this, $this->getPathsToExclude());
$this->tempStore->set(self::TEMPSTORE_APPLY_TIME_KEY, $this->time->getRequestTime());
$this->dispatch($event, $this->setNotApplying(...));
// Create a marker file so that we can tell later on if the commit failed.
$this->failureMarker->write($this, $this->getFailureMarkerMessage());
// Exclude the failure file from the commit operation.
$paths_to_exclude = new PathList(...$event->getExcludedPaths());
$paths_to_exclude->add(
str_replace($this->pathLocator->getProjectRoot() . DIRECTORY_SEPARATOR, '', $this->failureMarker->getPath()),
);
try {
$this->committer->commit($stage_dir, $active_dir, $paths_to_exclude, NULL, $timeout);
$this->committer->commit($stage_dir, $active_dir, $excluded_paths, NULL, $timeout);
}
catch (InvalidArgumentException | PreconditionException $e) {
// The commit operation has not started yet, so we can clear the failure
......@@ -536,26 +579,16 @@ abstract class StageBase implements LoggerAwareInterface {
throw new StageException($this, 'Cannot destroy the stage directory while it is being applied to the active directory.');
}
$this->dispatch(new PreDestroyEvent($this));
$staging_root = $this->getStagingRoot();
// If the stage root directory exists, delete it and everything in it.
if (file_exists($staging_root)) {
try {
$this->fileSystem->deleteRecursive($staging_root, function (string $path): void {
$this->fileSystem->chmod($path, 0777);
});
}
catch (FileException) {
// Deliberately swallow the exception so that the stage will be marked
// as available and the post-destroy event will be fired, even if the
// stage directory can't actually be deleted. The file system service
// logs the exception, so we don't need to do anything else here.
}
// If the stage directory exists, queue it to be automatically cleaned up
// later by a queue (which may or may not happen during cron).
// @see \Drupal\package_manager\Plugin\QueueWorker\Cleaner
if ($this->stageDirectoryExists()) {
$this->queueFactory->get('package_manager_cleanup')
->createItem($this->getStageDirectory());
}
$this->storeDestroyInfo($force, $message);
$this->markAsAvailable();
$this->dispatch(new PostDestroyEvent($this));
}
/**
......@@ -595,6 +628,8 @@ abstract class StageBase implements LoggerAwareInterface {
}
if (isset($error)) {
// Ensure the error is logged for post-mortem diagnostics.
Error::logException($this->logger, $error);
if ($on_error) {
$on_error();
}
......@@ -648,7 +683,7 @@ abstract class StageBase implements LoggerAwareInterface {
)->render());
}
if ($stored_lock === [$unique_id, static::class]) {
if ($stored_lock === [$unique_id, static::class, $this->getType()]) {
$this->lock = $stored_lock;
return $this;
}
......
......@@ -42,22 +42,12 @@ trait StatusCheckTrait {
try {
$paths_to_exclude_event = new CollectPathsToExcludeEvent($stage, $path_locator, $path_factory);
$event_dispatcher->dispatch($paths_to_exclude_event);
$event = new StatusCheckEvent($stage, $paths_to_exclude_event->getAll());
}
catch (\Throwable $throwable) {
// We can dispatch the status check event without the paths to exclude,
// but it must be set explicitly to NULL, to allow those status checks to
// run that do not need the paths to exclude.
$event = new StatusCheckEvent($stage, NULL);
// Add the error that was encountered so that regardless of any other
// validation errors BaseRequirementsFulfilledValidator will stop the
// event propagation after the base requirement validators have run.
// @see \Drupal\package_manager\Validator\BaseRequirementsFulfilledValidator
$event->addErrorFromThrowable($throwable, t('Unable to collect the paths to exclude.'));
$paths_to_exclude_event = $throwable;
}
$event_dispatcher->dispatch($event);
return $event->getResults();
$event = new StatusCheckEvent($stage, $paths_to_exclude_event);
return $event_dispatcher->dispatch($event)->getResults();
}
}
......@@ -36,7 +36,7 @@ final class TranslatableStringAdapter extends TranslatableMarkup implements Tran
/**
* {@inheritdoc}
*/
public function trans(TranslatorInterface $translator, ?string $locale = NULL): string {
public function trans(?TranslatorInterface $translator = NULL, ?string $locale = NULL): string {
// This method is NEVER used by Drupal to translate the underlying string;
// it exists solely for Composer Stager's translation system to
// transparently translate Drupal strings using its own architecture.
......
......@@ -9,7 +9,6 @@ use PhpTuf\ComposerStager\API\Translation\Factory\TranslatableFactoryInterface;
use PhpTuf\ComposerStager\API\Translation\Service\DomainOptionsInterface;
use PhpTuf\ComposerStager\API\Translation\Value\TranslatableInterface;
use PhpTuf\ComposerStager\API\Translation\Value\TranslationParametersInterface;
use PhpTuf\ComposerStager\Internal\Translation\Factory\TranslatableFactory as StagerTranslatableFactory;
/**
* Creates translatable strings that can interoperate with Composer Stager.
......@@ -24,13 +23,13 @@ final class TranslatableStringFactory implements TranslatableFactoryInterface {
/**
* Constructs a TranslatableStringFactory object.
*
* @param \PhpTuf\ComposerStager\Internal\Translation\Factory\TranslatableFactory $decorated
* @param \PhpTuf\ComposerStager\API\Translation\Factory\TranslatableFactoryInterface $decorated
* The decorated translatable factory service.
* @param \Drupal\Core\StringTranslation\TranslationInterface $translation
* The string translation service.
*/
public function __construct(
private readonly StagerTranslatableFactory $decorated,
private readonly TranslatableFactoryInterface $decorated,
private readonly TranslationInterface $translation,
) {}
......
......@@ -4,6 +4,7 @@ declare(strict_types = 1);
namespace Drupal\package_manager\Validator;
use Composer\Semver\Semver;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
......@@ -155,15 +156,26 @@ final class ComposerPatchesValidator implements EventSubscriberInterface {
*/
private function computePatcherStatus(string $working_dir): array {
$list = $this->composerInspector->getInstalledPackagesList($working_dir);
$is_installed = isset($list[static::PLUGIN_NAME]);
$installed_version = $list[static::PLUGIN_NAME]?->version;
$info = $this->composerInspector->getRootPackageInfo($working_dir);
$is_root_requirement = array_key_exists(static::PLUGIN_NAME, $info['requires'] ?? []) || array_key_exists(static::PLUGIN_NAME, $info['devRequires'] ?? []);
$extra = Json::decode($this->composerInspector->getConfig('extra', $working_dir));
$exit_on_failure = $extra['composer-exit-on-patch-failure'] ?? FALSE;
// The 2.x version of the plugin always exits with an error if a patch can't
// be applied.
if ($installed_version && Semver::satisfies($installed_version, '^2')) {
$exit_on_failure = TRUE;
}
else {
$extra = Json::decode($this->composerInspector->getConfig('extra', $working_dir));
$exit_on_failure = $extra['composer-exit-on-patch-failure'] ?? FALSE;
}
return [$is_installed, $is_root_requirement, $exit_on_failure];
return [
is_string($installed_version),
$is_root_requirement,
$exit_on_failure,
];
}
/**
......
......@@ -64,9 +64,10 @@ final class ComposerPluginsValidator implements EventSubscriberInterface {
private const SUPPORTED_PLUGINS_THAT_DO_MODIFY = [
// cSpell:disable
// @see \Drupal\package_manager\Validator\ComposerPatchesValidator
'cweagans/composer-patches' => '^1.7.3',
'cweagans/composer-patches' => '^1.7.3 || ^2',
// @see \Drupal\package_manager\PathExcluder\VendorHardeningExcluder
'drupal/core-vendor-hardening' => '*',
'php-http/discovery' => '*',
// cSpell:enable
];
......
......@@ -85,7 +85,7 @@ final class DuplicateInfoFileValidator implements EventSubscriberInterface {
* @return int[]
* Array of count of info.yml files in the directory keyed by file name.
*/
protected function findInfoFiles(string $dir): array {
private function findInfoFiles(string $dir): array {
// Use the official extension discovery mechanism, but tweak it, because by
// default it resolves duplicates.
// @see \Drupal\Core\Extension\ExtensionDiscovery::process()
......
......@@ -20,7 +20,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
final class EnvironmentSupportValidator implements EventSubscriberInterface {
use BaseRequirementValidatorTrait {
getSubscribedEvents as protected getSubscribedEventsFromTrait;
getSubscribedEvents as private getSubscribedEventsFromTrait;
}
use StringTranslationTrait;
......
......@@ -6,7 +6,7 @@ namespace Drupal\package_manager\Validator;
use Drupal\Core\State\StateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\package_manager\Event\PostDestroyEvent;
use Drupal\package_manager\Event\PostApplyEvent;
use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\PreOperationStageEvent;
......@@ -32,7 +32,7 @@ final class LockFileValidator implements EventSubscriberInterface {
*
* @var string
*/
protected const STATE_KEY = 'package_manager.lock_hash';
private const STATE_KEY = 'package_manager.lock_hash';
/**
* Constructs a LockFileValidator object.
......@@ -176,7 +176,7 @@ final class LockFileValidator implements EventSubscriberInterface {
PreRequireEvent::class => 'validate',
PreApplyEvent::class => 'validate',
StatusCheckEvent::class => 'validate',
PostDestroyEvent::class => 'deleteHash',
PostApplyEvent::class => 'deleteHash',
];
}
......
......@@ -48,7 +48,7 @@ final class MultisiteValidator implements EventSubscriberInterface {
* @return bool
* TRUE if the current site is part of a multisite, otherwise FALSE.
*/
protected function isMultisite(): bool {
private function isMultisite(): bool {
$web_root = $this->pathLocator->getWebRoot();
if ($web_root) {
$web_root .= '/';
......
......@@ -6,6 +6,9 @@ namespace Drupal\package_manager\Validator;
use Drupal\Component\FileSystem\FileSystem as DrupalFilesystem;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\PreOperationStageEvent;
use Drupal\package_manager\Event\StatusCheckEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
......@@ -59,17 +62,17 @@ class PhpExtensionsValidator implements EventSubscriberInterface {
}
/**
* Flags a warning if the OpenSSL extension is not installed.
* Flags an error if the OpenSSL extension is not installed.
*
* @param \Drupal\package_manager\Event\StatusCheckEvent $event
* @param \Drupal\package_manager\Event\PreOperationStageEvent $event
* The event object.
*/
public function validateOpenSsl(StatusCheckEvent $event): void {
public function validateOpenSsl(PreOperationStageEvent $event): void {
if (!$this->isExtensionLoaded('openssl')) {
$message = $this->t('The OpenSSL extension is not enabled, which is a security risk. See <a href=":url">the PHP documentation</a> for information on how to enable this extension.', [
':url' => 'https://www.php.net/manual/en/openssl.installation.php',
]);
$event->addWarning([$message]);
$event->addError([$message]);
}
}
......@@ -97,6 +100,8 @@ class PhpExtensionsValidator implements EventSubscriberInterface {
['validateXdebug'],
['validateOpenSsl'],
],
PreCreateEvent::class => ['validateOpenSsl'],
PreApplyEvent::class => ['validateOpenSsl'],
];
}
......