##// END OF EJS Templates
merge with stable
Augie Fackler -
r45285:cfe86fbc merge default
parent child Browse files
Show More
@@ -1,197 +1,198
1 1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
2 2 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
3 3 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys=
4 4 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4=
5 5 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I=
6 6 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU=
7 7 bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0=
8 8 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE=
9 9 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc=
10 10 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu
11 11 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE
12 12 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx
13 13 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx
14 14 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje
15 15 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM
16 16 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 0 iEYEABECAAYFAkpopLIACgkQywK+sNU5EO8QSgCfZ0ztsd071rOa2lhmp9Fyue/WoI0AoLTei80/xrhRlB8L/rZEf2KBl8dA
17 17 31ec469f9b556f11819937cf68ee53f2be927ebf 0 iEYEABECAAYFAksBuxAACgkQywK+sNU5EO+mBwCfagB+A0txzWZ6dRpug3LEoK7Z1QsAoKpbk8vsLjv6/oRDicSk/qBu33+m
18 18 439d7ea6fe3aa4ab9ec274a68846779153789de9 0 iEYEABECAAYFAksVw0kACgkQywK+sNU5EO/oZwCfdfBEkgp38xq6wN2F4nj+SzofrJIAnjmxt04vaJSeOOeHylHvk6lzuQsw
19 19 296a0b14a68621f6990c54fdba0083f6f20935bf 0 iEYEABECAAYFAks+jCoACgkQywK+sNU5EO9J8wCeMUGF9E/gS2UBsqIz56WS4HMPRPUAoI5J95mwEIK8Clrl7qFRidNI6APq
20 20 4aa619c4c2c09907034d9824ebb1dd0e878206eb 0 iEYEABECAAYFAktm9IsACgkQywK+sNU5EO9XGgCgk4HclRQhexEtooPE5GcUCdB6M8EAn2ptOhMVbIoO+JncA+tNACPFXh0O
21 21 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 0 iEYEABECAAYFAkuRoSQACgkQywK+sNU5EO//3QCeJDc5r2uFyFCtAlpSA27DEE5rrxAAn2FSwTy9fhrB3QAdDQlwkEZcQzDh
22 22 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 0 iEYEABECAAYFAku1IwIACgkQywK+sNU5EO9MjgCdHLVwkTZlNHxhcznZKBL1rjN+J7cAoLLWi9LTL6f/TgBaPSKOy1ublbaW
23 23 39f725929f0c48c5fb3b90c071fc3066012456ca 0 iEYEABECAAYFAkvclvsACgkQywK+sNU5EO9FSwCeL9i5x8ALW/LE5+lCX6MFEAe4MhwAn1ev5o6SX6GrNdDfKweiemfO2VBk
24 24 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 0 iEYEABECAAYFAkvsKTkACgkQywK+sNU5EO9qEACgiSiRGvTG2vXGJ65tUSOIYihTuFAAnRzRIqEVSw8M8/RGeUXRps0IzaCO
25 25 24fe2629c6fd0c74c90bd066e77387c2b02e8437 0 iEYEABECAAYFAkwFLRsACgkQywK+sNU5EO+pJACgp13tPI+pbwKZV+LeMjcQ4H6tCZYAoJebzhd6a8yYx6qiwpJxA9BXZNXy
26 26 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 0 iEYEABECAAYFAkwsyxcACgkQywK+sNU5EO+crACfUpNAF57PmClkSri9nJcBjb2goN4AniPCNaKvnki7TnUsi1u2oxltpKKL
27 27 bf1774d95bde614af3956d92b20e2a0c68c5fec7 0 iEYEABECAAYFAkxVwccACgkQywK+sNU5EO+oFQCeJzwZ+we1fIIyBGCddHceOUAN++cAnjvT6A8ZWW0zV21NXIFF1qQmjxJd
28 28 c00f03a4982e467fb6b6bd45908767db6df4771d 0 iEYEABECAAYFAkxXDqsACgkQywK+sNU5EO/GJACfT9Rz4hZOxPQEs91JwtmfjevO84gAmwSmtfo5mmWSm8gtTUebCcdTv0Kf
29 29 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 0 iD8DBQBMdo+qywK+sNU5EO8RAqQpAJ975BL2CCAiWMz9SXthNQ9xG181IwCgp4O+KViHPkufZVFn2aTKMNvcr1A=
30 30 93d8bff78c96fe7e33237b257558ee97290048a4 0 iD8DBQBMpfvdywK+sNU5EO8RAsxVAJ0UaL1XB51C76JUBhafc9GBefuMxwCdEWkTOzwvE0SarJBe9i008jhbqW4=
31 31 333421b9e0f96c7bc788e5667c146a58a9440a55 0 iD8DBQBMz0HOywK+sNU5EO8RAlsEAJ0USh6yOG7OrWkADGunVt9QimBQnwCbBqeMnKgSbwEw8jZwE3Iz1mdrYlo=
32 32 4438875ec01bd0fc32be92b0872eb6daeed4d44f 0 iD8DBQBM4WYUywK+sNU5EO8RAhCVAJ0dJswachwFAHALmk1x0RJehxzqPQCbBNskP9n/X689jB+btNTZTyKU/fw=
33 33 6aff4f144ad356311318b0011df0bb21f2c97429 0 iD8DBQBM9uxXywK+sNU5EO8RAv+4AKCDj4qKP16GdPaq1tP6BUwpM/M1OACfRyzLPp/qiiN8xJTWoWYSe/XjJug=
34 34 e3bf16703e2601de99e563cdb3a5d50b64e6d320 0 iD8DBQBNH8WqywK+sNU5EO8RAiQTAJ9sBO+TeiGro4si77VVaQaA6jcRUgCfSA28dBbjj0oFoQwvPoZjANiZBH8=
35 35 a6c855c32ea081da3c3b8ff628f1847ff271482f 0 iD8DBQBNSJJ+ywK+sNU5EO8RAoJaAKCweDEF70fu+r1Zn7pYDXdlk5RuSgCeO9gK/eit8Lin/1n3pO7aYguFLok=
36 36 2b2155623ee2559caf288fd333f30475966c4525 0 iD8DBQBNSJeBywK+sNU5EO8RAm1KAJ4hW9Cm9nHaaGJguchBaPLlAr+O3wCgqgmMok8bdAS06N6PL60PSTM//Gg=
37 37 2616325766e3504c8ae7c84bd15ee610901fe91d 0 iD8DBQBNbWy9ywK+sNU5EO8RAlWCAJ4mW8HbzjJj9GpK98muX7k+7EvEHwCfaTLbC/DH3QEsZBhEP+M8tzL6RU4=
38 38 aa1f3be38ab127280761889d2dca906ca465b5f4 0 iD8DBQBNeQq7ywK+sNU5EO8RAlEOAJ4tlEDdetE9lKfjGgjbkcR8PrC3egCfXCfF3qNVvU/2YYjpgvRwevjvDy0=
39 39 b032bec2c0a651ca0ddecb65714bfe6770f67d70 0 iD8DBQBNlg5kywK+sNU5EO8RAnGEAJ9gmEx6MfaR4XcG2m/93vwtfyzs3gCgltzx8/YdHPwqDwRX/WbpYgi33is=
40 40 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
41 41 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
42 42 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
43 43 4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik=
44 44 d629f1e89021103f1753addcef6b310e4435b184 0 iD8DBQBOWAsBywK+sNU5EO8RAht4AJwJl9oNFopuGkj5m8aKuf7bqPkoAQCeNrEm7UhFsZKYT5iUOjnMV7s2LaM=
45 45 351a9292e430e35766c552066ed3e87c557b803b 0 iD8DBQBOh3zUywK+sNU5EO8RApFMAKCD3Y/u3avDFndznwqfG5UeTHMlvACfUivPIVQZyDZnhZMq0UhC6zhCEQg=
46 46 384082750f2c51dc917d85a7145748330fa6ef4d 0 iD8DBQBOmd+OywK+sNU5EO8RAgDgAJ9V/X+G7VLwhTpHrZNiOHabzSyzYQCdE2kKfIevJUYB9QLAWCWP6DPwrwI=
47 47 41453d55b481ddfcc1dacb445179649e24ca861d 0 iD8DBQBOsFhpywK+sNU5EO8RAqM6AKCyfxUae3/zLuiLdQz+JR78690eMACfQ6JTBQib4AbE+rUDdkeFYg9K/+4=
48 48 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 0 iD8DBQBO1/fWywK+sNU5EO8RAmoPAKCR5lpv1D6JLURHD8KVLSV4GRVEBgCgnd0Sy78ligNfqAMafmACRDvj7vo=
49 49 6344043924497cd06d781d9014c66802285072e4 0 iD8DBQBPALgmywK+sNU5EO8RAlfhAJ9nYOdWnhfVDHYtDTJAyJtXBAQS9wCgnefoSQt7QABkbGxM+Q85UYEBuD0=
50 50 db33555eafeaf9df1e18950e29439eaa706d399b 0 iD8DBQBPGdzxywK+sNU5EO8RAppkAJ9jOXhUVE/97CPgiMA0pMGiIYnesQCfengAszcBiSiKGugiI8Okc9ghU+Y=
51 51 2aa5b51f310fb3befd26bed99c02267f5c12c734 0 iD8DBQBPKZ9bywK+sNU5EO8RAt1TAJ45r1eJ0YqSkInzrrayg4TVCh0SnQCgm0GA/Ua74jnnDwVQ60lAwROuz1Q=
52 52 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 0 iD8DBQBPT/fvywK+sNU5EO8RAnfYAKCn7d0vwqIb100YfWm1F7nFD5B+FACeM02YHpQLSNsztrBCObtqcnfod7Q=
53 53 b9bd95e61b49c221c4cca24e6da7c946fc02f992 0 iD8DBQBPeLsIywK+sNU5EO8RAvpNAKCtKe2gitz8dYn52IRF0hFOPCR7AQCfRJL/RWCFweu2T1vH/mUOCf8SXXc=
54 54 d9e2f09d5488c395ae9ddbb320ceacd24757e055 0 iD8DBQBPju/dywK+sNU5EO8RArBYAJ9xtifdbk+hCOJO8OZa4JfHX8OYZQCeKPMBaBWiT8N/WHoOm1XU0q+iono=
55 55 00182b3d087909e3c3ae44761efecdde8f319ef3 0 iD8DBQBPoFhIywK+sNU5EO8RAhzhAKCBj1n2jxPTkZNJJ5pSp3soa+XHIgCgsZZpAQxOpXwCp0eCdNGe0+pmxmg=
56 56 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 0 iD8DBQBPovNWywK+sNU5EO8RAhgiAJ980T91FdPTRMmVONDhpkMsZwVIMACgg3bKvoWSeuCW28llUhAJtUjrMv0=
57 57 85a358df5bbbe404ca25730c9c459b34263441dc 0 iD8DBQBPyZsWywK+sNU5EO8RAnpLAJ48qrGDJRT+pteS0mSQ11haqHstPwCdG4ccGbk+0JHb7aNy8/NRGAOqn9w=
58 58 b013baa3898e117959984fc64c29d8c784d2f28b 0 iD8DBQBP8QOPywK+sNU5EO8RAqimAKCFRSx0lvG6y8vne2IhNG062Hn0dACeMLI5/zhpWpHBIVeAAquYfx2XFeA=
59 59 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 0 iD8DBQBQGiL8ywK+sNU5EO8RAq5oAJ4rMMCPx6O+OuzNXVOexogedWz/QgCeIiIxLd76I4pXO48tdXhr0hQcBuM=
60 60 072209ae4ddb654eb2d5fd35bff358c738414432 0 iD8DBQBQQkq0ywK+sNU5EO8RArDTAJ9nk5CySnNAjAXYvqvx4uWCw9ThZwCgqmFRehH/l+oTwj3f8nw8u8qTCdc=
61 61 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 0 iD8DBQBQamltywK+sNU5EO8RAlsqAJ4qF/m6aFu4mJCOKTiAP5RvZFK02ACfawYShUZO6OXEFfveU0aAxDR0M1k=
62 62 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 0 iD8DBQBQgPV5ywK+sNU5EO8RArylAJ0abcx5NlDjyv3ZDWpAfRIHyRsJtQCgn4TMuEayqgxzrvadQZHdTEU2g38=
63 63 195ad823b5d58c68903a6153a25e3fb4ed25239d 0 iD8DBQBQkuT9ywK+sNU5EO8RAhB4AKCeerItoK2Jipm2cVf4euGofAa/WACeJj3TVd4pFILpb+ogj7ebweFLJi0=
64 64 0c10cf8191469e7c3c8844922e17e71a176cb7cb 0 iD8DBQBQvQWoywK+sNU5EO8RAnq3AJoCn98u4geFx5YaQaeh99gFhCd7bQCgjoBwBSUyOvGd0yBy60E3Vv3VZhM=
65 65 a4765077b65e6ae29ba42bab7834717b5072d5ba 0 iD8DBQBQ486sywK+sNU5EO8RAhmJAJ90aLfLKZhmcZN7kqphigQJxiFOQACeJ5IUZxjGKH4xzi3MrgIcx9n+dB0=
66 66 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 0 iD8DBQBQ+yuYywK+sNU5EO8RAm9JAJoD/UciWvpGeKBcpGtZJBFJVcL/HACghDXSgQ+xQDjB+6uGrdgAQsRR1Lg=
67 67 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 0 iD8DBQBRDDROywK+sNU5EO8RAh75AJ9uJCGoCWnP0Lv/+XuYs4hvUl+sAgCcD36QgAnuw8IQXrvv684BAXAnHcA=
68 68 7511d4df752e61fe7ae4f3682e0a0008573b0402 0 iD8DBQBRFYaoywK+sNU5EO8RAuErAJoDyhXn+lptU3+AevVdwAIeNFyR2gCdHzPHyWd+JDeWCUR+pSOBi8O2ppM=
69 69 5b7175377babacce80a6c1e12366d8032a6d4340 0 iD8DBQBRMCYgywK+sNU5EO8RAq1/AKCWKlt9ysibyQgYwoxxIOZv5J8rpwCcDSHQaaf1fFZUTnQsOePwcM2Y/Sg=
70 70 50c922c1b5145dab8baefefb0437d363b6a6c21c 0 iD8DBQBRWnUnywK+sNU5EO8RAuQRAJwM42cJqJPeqJ0jVNdMqKMDqr4dSACeP0cRVGz1gitMuV0x8f3mrZrqc7I=
71 71 8a7bd2dccd44ed571afe7424cd7f95594f27c092 0 iD8DBQBRXfBvywK+sNU5EO8RAn+LAKCsMmflbuXjYRxlzFwId5ptm8TZcwCdGkyLbZcASBOkzQUm/WW1qfknJHU=
72 72 292cd385856d98bacb2c3086f8897bc660c2beea 0 iD8DBQBRcM0BywK+sNU5EO8RAjp4AKCJBykQbvXhKuvLSMxKx3a2TBiXcACfbr/kLg5GlZTF/XDPmY+PyHgI/GM=
73 73 23f785b38af38d2fca6b8f3db56b8007a84cd73a 0 iD8DBQBRgZwNywK+sNU5EO8RAmO4AJ4u2ILGuimRP6MJgE2t65LZ5dAdkACgiENEstIdrlFC80p+sWKD81kKIYI=
74 74 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 0 iD8DBQBRkswvywK+sNU5EO8RAiYYAJsHTHyHbJeAgmGvBTmDrfcKu4doUgCeLm7eGBjx7yAPUvEtxef8rAkQmXI=
75 75 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 0 iD8DBQBRqnFLywK+sNU5EO8RAsWNAJ9RR6t+y1DLFc2HeH0eN9VfZAKF9gCeJ8ezvhtKq/LMs0/nvcgKQc/d5jk=
76 76 009794acc6e37a650f0fae37872e733382ac1c0c 0 iD8DBQBR0guxywK+sNU5EO8RArNkAKCq9pMihVzP8Os5kCmgbWpe5C37wgCgqzuPZTHvAsXF5wTyaSTMVa9Ccq4=
77 77 f0d7721d7322dcfb5af33599c2543f27335334bb 0 iD8DBQBR8taaywK+sNU5EO8RAqeEAJ4idDhhDuEsgsUjeQgWNj498matHACfT67gSF5w0ylsrBx1Hb52HkGXDm0=
78 78 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 0 iD8DBQBR+ymFywK+sNU5EO8RAuSdAJkBMcd9DAZ3rWE9WGKPm2YZ8LBoXACfXn/wbEsVy7ZgJoUwiWmHSnQaWCI=
79 79 335a558f81dc73afeab4d7be63617392b130117f 0 iQIVAwUAUiZrIyBXgaxoKi1yAQK2iw//cquNqqSkc8Re5/TZT9I6NH+lh6DbOKjJP0Xl1Wqq0K+KSIUgZG4G32ovaEb2l5X0uY+3unRPiZ0ebl0YSw4Fb2ZiPIADXLBTOYRrY2Wwd3tpJeGI6wEgZt3SfcITV/g7NJrCjT3FlYoSOIayrExM80InSdcEM0Q3Rx6HKzY2acyxzgZeAtAW5ohFvHilSvY6p5Gcm4+QptMxvw45GPdreUmjeXZxNXNXZ8P+MjMz/QJbai/N7PjmK8lqnhkBsT48Ng/KhhmOkGntNJ2/ImBWLFGcWngSvJ7sfWwnyhndvGhe0Hq1NcCf7I8TjNDxU5TR+m+uW7xjXdLoDbUjBdX4sKXnh8ZjbYiODKBOrrDq25cf8nA/tnpKyE/qsVy60kOk6loY4XKiYmn1V49Ta0emmDx0hqo3HgxHHsHX0NDnGdWGol7cPRET0RzVobKq1A0jnrhPooWidvLh9bPzLonrWDo+ib+DuySoRkuYUK4pgZJ2mbg6daFOBEZygkSyRB8bo1UQUP7EgQDrWe4khb/5GHEfDkrQz3qu/sXvc0Ir1mOUWBFPHC2DjjCn/oMJuUkG1SwM8l2Bfv7h67ssES6YQ2+RjOix4yid7EXS/Ogl45PzCIPSI5+BbNs10JhE0w5uErBHlF53EDTe/TSLc+GU6DB6PP6dH912Njdr3jpNSUQ=
80 80 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
@@ -1,210 +1,211
1 1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
2 2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
3 3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
4 4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
5 5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
6 6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
7 7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
8 8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
9 9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
10 10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
11 11 3a56574f329a368d645853e0f9e09472aee62349 0.8
12 12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
13 13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
14 14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
15 15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
16 16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
17 17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
18 18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
19 19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
20 20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
21 21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
22 22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
23 23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
24 24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
25 25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
26 26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
27 27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
28 28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
29 29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
30 30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
31 31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
32 32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
33 33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
34 34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
35 35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
36 36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
37 37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
38 38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
39 39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
40 40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
41 41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
42 42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
43 43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
44 44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
45 45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
46 46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
47 47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
48 48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
49 49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
50 50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
51 51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
52 52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
53 53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
54 54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
55 55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
56 56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
57 57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
58 58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
59 59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
60 60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
61 61 6344043924497cd06d781d9014c66802285072e4 2.0.2
62 62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
63 63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
64 64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
65 65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
66 66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
67 67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
68 68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
69 69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
70 70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
71 71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
72 72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
73 73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
74 74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
75 75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
76 76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
77 77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
78 78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
79 79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
80 80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
81 81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
82 82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
83 83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
84 84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
85 85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
86 86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
87 87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
88 88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
89 89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
90 90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
91 91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
92 92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
93 93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
94 94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
95 95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
96 96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
97 97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
98 98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
99 99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
100 100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
101 101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
102 102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
103 103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
104 104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
105 105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
106 106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
107 107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
108 108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
109 109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
110 110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
111 111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
112 112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
113 113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
114 114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
115 115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
116 116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
117 117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
118 118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
119 119 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2
120 120 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3
121 121 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc
122 122 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4
123 123 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1
124 124 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2
125 125 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc
126 126 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5
127 127 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1
128 128 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2
129 129 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc
130 130 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6
131 131 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1
132 132 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2
133 133 ea389970c08449440587712117f178d33bab3f1e 3.6.3
134 134 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc
135 135 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7
136 136 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1
137 137 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2
138 138 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3
139 139 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc
140 140 f85de28eae32e7d3064b1a1321309071bbaaa069 3.8
141 141 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1
142 142 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2
143 143 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3
144 144 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4
145 145 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc
146 146 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9
147 147 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1
148 148 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2
149 149 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc
150 150 eab27446995210c334c3d06f1a659e3b9b5da769 4.0
151 151 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1
152 152 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2
153 153 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc
154 154 e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1
155 155 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1
156 156 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2
157 157 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3
158 158 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc
159 159 bb96d4a497432722623ae60d9bc734a1e360179e 4.2
160 160 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1
161 161 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2
162 162 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc
163 163 5544af8622863796a0027566f6b646e10d522c4c 4.3
164 164 943c91326b23954e6e1c6960d0239511f9530258 4.2.3
165 165 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
166 166 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2
167 167 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3
168 168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
169 169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
170 170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
171 171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
172 172 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
173 173 d334afc585e29577f271c5eda03378736a16ca6b 4.5
174 174 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
175 175 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
176 176 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
177 177 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
178 178 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
179 179 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
180 180 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
181 181 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
182 182 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
183 183 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
184 184 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1
185 185 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
186 186 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
187 187 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
188 188 1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
189 189 197f092b2cd9691e2a55d198f717b231af9be6f9 4.8.2
190 190 593718ff5844cad7a27ee3eb5adad89ac8550949 4.9rc0
191 191 83377b4b4ae0e9a6b8e579f7b0a693b8cf5c3b10 4.9
192 192 4ea21df312ec7159c5b3633096b6ecf68750b0dd 4.9.1
193 193 4a8d9ed864754837a185a642170cde24392f9abf 5.0rc0
194 194 07e479ef7c9639be0029f00e6a722b96dcc05fee 5.0
195 195 c3484ddbdb9621256d597ed86b90d229c59c2af9 5.0.1
196 196 97ada9b8d51bef24c5cb4cdca4243f0db694ab6e 5.0.2
197 197 e386b5f4f8360dbb43a576dd9b1368e386fefa5b 5.1rc0
198 198 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 5.1
199 199 a4e32fd539ab41489a51b2aa88bda9a73b839562 5.1.1
200 200 181e52f2b62f4768aa0d988936c929dc7c4a41a0 5.1.2
201 201 59338f9561099de77c684c00f76507f11e46ebe8 5.2rc0
202 202 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2
203 203 a50fecefa691c9b72a99e49aa6fe9dd13943c2bf 5.2.1
204 204 b4c82b70418022e67cc0e69b1aa3c3aa43aa1d29 5.2.2
205 205 84a0102c05c7852c8215ef6cf21d809927586b69 5.3rc0
206 206 e4344e463c0c888a2f437b78b5982ecdf3f6650a 5.3rc1
207 207 7f5410dfc8a64bb587d19637deb95d378fd1eb5c 5.3
208 208 6d121acbb82e65fe4dd3c2318a1b61981b958492 5.3.1
209 209 8fca7e8449a847e3cf1054f2c07b51237699fad3 5.3.2
210 210 26ce8e7515036d3431a03aaeb7bc72dd96cb1112 5.4rc0
211 cf3e07d7648a4371ce584d15dd692e7a6845792f 5.4
@@ -1,2272 +1,2285
1 1 # phabricator.py - simple Phabricator integration
2 2 #
3 3 # Copyright 2017 Facebook, Inc.
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7 """simple Phabricator integration (EXPERIMENTAL)
8 8
9 9 This extension provides a ``phabsend`` command which sends a stack of
10 10 changesets to Phabricator, and a ``phabread`` command which prints a stack of
11 11 revisions in a format suitable for :hg:`import`, and a ``phabupdate`` command
12 12 to update statuses in batch.
13 13
14 14 A "phabstatus" view for :hg:`show` is also provided; it displays status
15 15 information of Phabricator differentials associated with unfinished
16 16 changesets.
17 17
18 18 By default, Phabricator requires ``Test Plan`` which might prevent some
19 19 changeset from being sent. The requirement could be disabled by changing
20 20 ``differential.require-test-plan-field`` config server side.
21 21
22 22 Config::
23 23
24 24 [phabricator]
25 25 # Phabricator URL
26 26 url = https://phab.example.com/
27 27
28 28 # Repo callsign. If a repo has a URL https://$HOST/diffusion/FOO, then its
29 29 # callsign is "FOO".
30 30 callsign = FOO
31 31
32 32 # curl command to use. If not set (default), use builtin HTTP library to
33 33 # communicate. If set, use the specified curl command. This could be useful
34 34 # if you need to specify advanced options that is not easily supported by
35 35 # the internal library.
36 36 curlcmd = curl --connect-timeout 2 --retry 3 --silent
37 37
38 38 [auth]
39 39 example.schemes = https
40 40 example.prefix = phab.example.com
41 41
42 42 # API token. Get it from https://$HOST/conduit/login/
43 43 example.phabtoken = cli-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
44 44 """
45 45
46 46 from __future__ import absolute_import
47 47
48 48 import base64
49 49 import contextlib
50 50 import hashlib
51 51 import itertools
52 52 import json
53 53 import mimetypes
54 54 import operator
55 55 import re
56 56
57 57 from mercurial.node import bin, nullid, short
58 58 from mercurial.i18n import _
59 59 from mercurial.pycompat import getattr
60 60 from mercurial.thirdparty import attr
61 61 from mercurial import (
62 62 cmdutil,
63 63 context,
64 64 copies,
65 65 encoding,
66 66 error,
67 67 exthelper,
68 68 graphmod,
69 69 httpconnection as httpconnectionmod,
70 70 localrepo,
71 71 logcmdutil,
72 72 match,
73 73 mdiff,
74 74 obsutil,
75 75 parser,
76 76 patch,
77 77 phases,
78 78 pycompat,
79 79 scmutil,
80 80 smartset,
81 81 tags,
82 82 templatefilters,
83 83 templateutil,
84 84 url as urlmod,
85 85 util,
86 86 )
87 87 from mercurial.utils import (
88 88 procutil,
89 89 stringutil,
90 90 )
91 91 from . import show
92 92
93 93
94 94 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
95 95 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
96 96 # be specifying the version(s) of Mercurial they are tested with, or
97 97 # leave the attribute unspecified.
98 98 testedwith = b'ships-with-hg-core'
99 99
100 100 eh = exthelper.exthelper()
101 101
102 102 cmdtable = eh.cmdtable
103 103 command = eh.command
104 104 configtable = eh.configtable
105 105 templatekeyword = eh.templatekeyword
106 106 uisetup = eh.finaluisetup
107 107
108 108 # developer config: phabricator.batchsize
109 109 eh.configitem(
110 110 b'phabricator', b'batchsize', default=12,
111 111 )
112 112 eh.configitem(
113 113 b'phabricator', b'callsign', default=None,
114 114 )
115 115 eh.configitem(
116 116 b'phabricator', b'curlcmd', default=None,
117 117 )
118 118 # developer config: phabricator.debug
119 119 eh.configitem(
120 120 b'phabricator', b'debug', default=False,
121 121 )
122 122 # developer config: phabricator.repophid
123 123 eh.configitem(
124 124 b'phabricator', b'repophid', default=None,
125 125 )
126 126 eh.configitem(
127 127 b'phabricator', b'url', default=None,
128 128 )
129 129 eh.configitem(
130 130 b'phabsend', b'confirm', default=False,
131 131 )
132 132 eh.configitem(
133 133 b'phabimport', b'secret', default=False,
134 134 )
135 135 eh.configitem(
136 136 b'phabimport', b'obsolete', default=False,
137 137 )
138 138
139 139 colortable = {
140 140 b'phabricator.action.created': b'green',
141 141 b'phabricator.action.skipped': b'magenta',
142 142 b'phabricator.action.updated': b'magenta',
143 143 b'phabricator.desc': b'',
144 144 b'phabricator.drev': b'bold',
145 145 b'phabricator.node': b'',
146 146 b'phabricator.status.abandoned': b'magenta dim',
147 147 b'phabricator.status.accepted': b'green bold',
148 148 b'phabricator.status.closed': b'green',
149 149 b'phabricator.status.needsreview': b'yellow',
150 150 b'phabricator.status.needsrevision': b'red',
151 151 b'phabricator.status.changesplanned': b'red',
152 152 }
153 153
154 154 _VCR_FLAGS = [
155 155 (
156 156 b'',
157 157 b'test-vcr',
158 158 b'',
159 159 _(
160 160 b'Path to a vcr file. If nonexistent, will record a new vcr transcript'
161 161 b', otherwise will mock all http requests using the specified vcr file.'
162 162 b' (ADVANCED)'
163 163 ),
164 164 ),
165 165 ]
166 166
167 167
168 168 @eh.wrapfunction(localrepo, "loadhgrc")
169 169 def _loadhgrc(orig, ui, wdirvfs, hgvfs, requirements):
170 170 """Load ``.arcconfig`` content into a ui instance on repository open.
171 171 """
172 172 result = False
173 173 arcconfig = {}
174 174
175 175 try:
176 176 # json.loads only accepts bytes from 3.6+
177 177 rawparams = encoding.unifromlocal(wdirvfs.read(b".arcconfig"))
178 178 # json.loads only returns unicode strings
179 179 arcconfig = pycompat.rapply(
180 180 lambda x: encoding.unitolocal(x)
181 181 if isinstance(x, pycompat.unicode)
182 182 else x,
183 183 pycompat.json_loads(rawparams),
184 184 )
185 185
186 186 result = True
187 187 except ValueError:
188 188 ui.warn(_(b"invalid JSON in %s\n") % wdirvfs.join(b".arcconfig"))
189 189 except IOError:
190 190 pass
191 191
192 192 cfg = util.sortdict()
193 193
194 194 if b"repository.callsign" in arcconfig:
195 195 cfg[(b"phabricator", b"callsign")] = arcconfig[b"repository.callsign"]
196 196
197 197 if b"phabricator.uri" in arcconfig:
198 198 cfg[(b"phabricator", b"url")] = arcconfig[b"phabricator.uri"]
199 199
200 200 if cfg:
201 201 ui.applyconfig(cfg, source=wdirvfs.join(b".arcconfig"))
202 202
203 203 return orig(ui, wdirvfs, hgvfs, requirements) or result # Load .hg/hgrc
204 204
205 205
206 206 def vcrcommand(name, flags, spec, helpcategory=None, optionalrepo=False):
207 207 fullflags = flags + _VCR_FLAGS
208 208
209 209 def hgmatcher(r1, r2):
210 210 if r1.uri != r2.uri or r1.method != r2.method:
211 211 return False
212 212 r1params = util.urlreq.parseqs(r1.body)
213 213 r2params = util.urlreq.parseqs(r2.body)
214 214 for key in r1params:
215 215 if key not in r2params:
216 216 return False
217 217 value = r1params[key][0]
218 218 # we want to compare json payloads without worrying about ordering
219 219 if value.startswith(b'{') and value.endswith(b'}'):
220 220 r1json = pycompat.json_loads(value)
221 221 r2json = pycompat.json_loads(r2params[key][0])
222 222 if r1json != r2json:
223 223 return False
224 224 elif r2params[key][0] != value:
225 225 return False
226 226 return True
227 227
228 228 def sanitiserequest(request):
229 229 request.body = re.sub(
230 230 br'cli-[a-z0-9]+', br'cli-hahayouwish', request.body
231 231 )
232 232 return request
233 233
234 234 def sanitiseresponse(response):
235 235 if 'set-cookie' in response['headers']:
236 236 del response['headers']['set-cookie']
237 237 return response
238 238
239 239 def decorate(fn):
240 240 def inner(*args, **kwargs):
241 241 cassette = pycompat.fsdecode(kwargs.pop('test_vcr', None))
242 242 if cassette:
243 243 import hgdemandimport
244 244
245 245 with hgdemandimport.deactivated():
246 246 import vcr as vcrmod
247 247 import vcr.stubs as stubs
248 248
249 249 vcr = vcrmod.VCR(
250 250 serializer='json',
251 251 before_record_request=sanitiserequest,
252 252 before_record_response=sanitiseresponse,
253 253 custom_patches=[
254 254 (
255 255 urlmod,
256 256 'httpconnection',
257 257 stubs.VCRHTTPConnection,
258 258 ),
259 259 (
260 260 urlmod,
261 261 'httpsconnection',
262 262 stubs.VCRHTTPSConnection,
263 263 ),
264 264 ],
265 265 )
266 266 vcr.register_matcher('hgmatcher', hgmatcher)
267 267 with vcr.use_cassette(cassette, match_on=['hgmatcher']):
268 268 return fn(*args, **kwargs)
269 269 return fn(*args, **kwargs)
270 270
271 271 cmd = util.checksignature(inner, depth=2)
272 272 cmd.__name__ = fn.__name__
273 273 cmd.__doc__ = fn.__doc__
274 274
275 275 return command(
276 276 name,
277 277 fullflags,
278 278 spec,
279 279 helpcategory=helpcategory,
280 280 optionalrepo=optionalrepo,
281 281 )(cmd)
282 282
283 283 return decorate
284 284
285 285
286 286 def _debug(ui, *msg, **opts):
287 287 """write debug output for Phabricator if ``phabricator.debug`` is set
288 288
289 289 Specifically, this avoids dumping Conduit and HTTP auth chatter that is
290 290 printed with the --debug argument.
291 291 """
292 292 if ui.configbool(b"phabricator", b"debug"):
293 293 flag = ui.debugflag
294 294 try:
295 295 ui.debugflag = True
296 296 ui.write(*msg, **opts)
297 297 finally:
298 298 ui.debugflag = flag
299 299
300 300
301 301 def urlencodenested(params):
302 302 """like urlencode, but works with nested parameters.
303 303
304 304 For example, if params is {'a': ['b', 'c'], 'd': {'e': 'f'}}, it will be
305 305 flattened to {'a[0]': 'b', 'a[1]': 'c', 'd[e]': 'f'} and then passed to
306 306 urlencode. Note: the encoding is consistent with PHP's http_build_query.
307 307 """
308 308 flatparams = util.sortdict()
309 309
310 310 def process(prefix, obj):
311 311 if isinstance(obj, bool):
312 312 obj = {True: b'true', False: b'false'}[obj] # Python -> PHP form
313 313 lister = lambda l: [(b'%d' % k, v) for k, v in enumerate(l)]
314 314 items = {list: lister, dict: lambda x: x.items()}.get(type(obj))
315 315 if items is None:
316 316 flatparams[prefix] = obj
317 317 else:
318 318 for k, v in items(obj):
319 319 if prefix:
320 320 process(b'%s[%s]' % (prefix, k), v)
321 321 else:
322 322 process(k, v)
323 323
324 324 process(b'', params)
325 325 return util.urlreq.urlencode(flatparams)
326 326
327 327
328 328 def readurltoken(ui):
329 329 """return conduit url, token and make sure they exist
330 330
331 331 Currently read from [auth] config section. In the future, it might
332 332 make sense to read from .arcconfig and .arcrc as well.
333 333 """
334 334 url = ui.config(b'phabricator', b'url')
335 335 if not url:
336 336 raise error.Abort(
337 337 _(b'config %s.%s is required') % (b'phabricator', b'url')
338 338 )
339 339
340 340 res = httpconnectionmod.readauthforuri(ui, url, util.url(url).user)
341 341 token = None
342 342
343 343 if res:
344 344 group, auth = res
345 345
346 346 ui.debug(b"using auth.%s.* for authentication\n" % group)
347 347
348 348 token = auth.get(b'phabtoken')
349 349
350 350 if not token:
351 351 raise error.Abort(
352 352 _(b'Can\'t find conduit token associated to %s') % (url,)
353 353 )
354 354
355 355 return url, token
356 356
357 357
358 358 def callconduit(ui, name, params):
359 359 """call Conduit API, params is a dict. return json.loads result, or None"""
360 360 host, token = readurltoken(ui)
361 361 url, authinfo = util.url(b'/'.join([host, b'api', name])).authinfo()
362 362 ui.debug(b'Conduit Call: %s %s\n' % (url, pycompat.byterepr(params)))
363 363 params = params.copy()
364 364 params[b'__conduit__'] = {
365 365 b'token': token,
366 366 }
367 367 rawdata = {
368 368 b'params': templatefilters.json(params),
369 369 b'output': b'json',
370 370 b'__conduit__': 1,
371 371 }
372 372 data = urlencodenested(rawdata)
373 373 curlcmd = ui.config(b'phabricator', b'curlcmd')
374 374 if curlcmd:
375 375 sin, sout = procutil.popen2(
376 376 b'%s -d @- %s' % (curlcmd, procutil.shellquote(url))
377 377 )
378 378 sin.write(data)
379 379 sin.close()
380 380 body = sout.read()
381 381 else:
382 382 urlopener = urlmod.opener(ui, authinfo)
383 383 request = util.urlreq.request(pycompat.strurl(url), data=data)
384 384 with contextlib.closing(urlopener.open(request)) as rsp:
385 385 body = rsp.read()
386 386 ui.debug(b'Conduit Response: %s\n' % body)
387 387 parsed = pycompat.rapply(
388 388 lambda x: encoding.unitolocal(x)
389 389 if isinstance(x, pycompat.unicode)
390 390 else x,
391 391 # json.loads only accepts bytes from py3.6+
392 392 pycompat.json_loads(encoding.unifromlocal(body)),
393 393 )
394 394 if parsed.get(b'error_code'):
395 395 msg = _(b'Conduit Error (%s): %s') % (
396 396 parsed[b'error_code'],
397 397 parsed[b'error_info'],
398 398 )
399 399 raise error.Abort(msg)
400 400 return parsed[b'result']
401 401
402 402
403 403 @vcrcommand(b'debugcallconduit', [], _(b'METHOD'), optionalrepo=True)
404 404 def debugcallconduit(ui, repo, name):
405 405 """call Conduit API
406 406
407 407 Call parameters are read from stdin as a JSON blob. Result will be written
408 408 to stdout as a JSON blob.
409 409 """
410 410 # json.loads only accepts bytes from 3.6+
411 411 rawparams = encoding.unifromlocal(ui.fin.read())
412 412 # json.loads only returns unicode strings
413 413 params = pycompat.rapply(
414 414 lambda x: encoding.unitolocal(x)
415 415 if isinstance(x, pycompat.unicode)
416 416 else x,
417 417 pycompat.json_loads(rawparams),
418 418 )
419 419 # json.dumps only accepts unicode strings
420 420 result = pycompat.rapply(
421 421 lambda x: encoding.unifromlocal(x) if isinstance(x, bytes) else x,
422 422 callconduit(ui, name, params),
423 423 )
424 424 s = json.dumps(result, sort_keys=True, indent=2, separators=(u',', u': '))
425 425 ui.write(b'%s\n' % encoding.unitolocal(s))
426 426
427 427
428 428 def getrepophid(repo):
429 429 """given callsign, return repository PHID or None"""
430 430 # developer config: phabricator.repophid
431 431 repophid = repo.ui.config(b'phabricator', b'repophid')
432 432 if repophid:
433 433 return repophid
434 434 callsign = repo.ui.config(b'phabricator', b'callsign')
435 435 if not callsign:
436 436 return None
437 437 query = callconduit(
438 438 repo.ui,
439 439 b'diffusion.repository.search',
440 440 {b'constraints': {b'callsigns': [callsign]}},
441 441 )
442 442 if len(query[b'data']) == 0:
443 443 return None
444 444 repophid = query[b'data'][0][b'phid']
445 445 repo.ui.setconfig(b'phabricator', b'repophid', repophid)
446 446 return repophid
447 447
448 448
449 449 _differentialrevisiontagre = re.compile(br'\AD([1-9][0-9]*)\Z')
450 450 _differentialrevisiondescre = re.compile(
451 451 br'^Differential Revision:\s*(?P<url>(?:.*)D(?P<id>[1-9][0-9]*))$', re.M
452 452 )
453 453
454 454
455 455 def getoldnodedrevmap(repo, nodelist):
456 456 """find previous nodes that has been sent to Phabricator
457 457
458 458 return {node: (oldnode, Differential diff, Differential Revision ID)}
459 459 for node in nodelist with known previous sent versions, or associated
460 460 Differential Revision IDs. ``oldnode`` and ``Differential diff`` could
461 461 be ``None``.
462 462
463 463 Examines commit messages like "Differential Revision:" to get the
464 464 association information.
465 465
466 466 If such commit message line is not found, examines all precursors and their
467 467 tags. Tags with format like "D1234" are considered a match and the node
468 468 with that tag, and the number after "D" (ex. 1234) will be returned.
469 469
470 470 The ``old node``, if not None, is guaranteed to be the last diff of
471 471 corresponding Differential Revision, and exist in the repo.
472 472 """
473 473 unfi = repo.unfiltered()
474 474 has_node = unfi.changelog.index.has_node
475 475
476 476 result = {} # {node: (oldnode?, lastdiff?, drev)}
477 477 # ordered for test stability when printing new -> old mapping below
478 478 toconfirm = util.sortdict() # {node: (force, {precnode}, drev)}
479 479 for node in nodelist:
480 480 ctx = unfi[node]
481 481 # For tags like "D123", put them into "toconfirm" to verify later
482 482 precnodes = list(obsutil.allpredecessors(unfi.obsstore, [node]))
483 483 for n in precnodes:
484 484 if has_node(n):
485 485 for tag in unfi.nodetags(n):
486 486 m = _differentialrevisiontagre.match(tag)
487 487 if m:
488 488 toconfirm[node] = (0, set(precnodes), int(m.group(1)))
489 489 break
490 490 else:
491 491 continue # move to next predecessor
492 492 break # found a tag, stop
493 493 else:
494 494 # Check commit message
495 495 m = _differentialrevisiondescre.search(ctx.description())
496 496 if m:
497 497 toconfirm[node] = (1, set(precnodes), int(m.group('id')))
498 498
499 499 # Double check if tags are genuine by collecting all old nodes from
500 500 # Phabricator, and expect precursors overlap with it.
501 501 if toconfirm:
502 502 drevs = [drev for force, precs, drev in toconfirm.values()]
503 503 alldiffs = callconduit(
504 504 unfi.ui, b'differential.querydiffs', {b'revisionIDs': drevs}
505 505 )
506 506
507 507 def getnodes(d, precset):
508 508 # Ignore other nodes that were combined into the Differential
509 509 # that aren't predecessors of the current local node.
510 510 return [n for n in getlocalcommits(d) if n in precset]
511 511
512 512 for newnode, (force, precset, drev) in toconfirm.items():
513 513 diffs = [
514 514 d for d in alldiffs.values() if int(d[b'revisionID']) == drev
515 515 ]
516 516
517 517 # local predecessors known by Phabricator
518 518 phprecset = {n for d in diffs for n in getnodes(d, precset)}
519 519
520 520 # Ignore if precursors (Phabricator and local repo) do not overlap,
521 521 # and force is not set (when commit message says nothing)
522 522 if not force and not phprecset:
523 523 tagname = b'D%d' % drev
524 524 tags.tag(
525 525 repo,
526 526 tagname,
527 527 nullid,
528 528 message=None,
529 529 user=None,
530 530 date=None,
531 531 local=True,
532 532 )
533 533 unfi.ui.warn(
534 534 _(
535 535 b'D%d: local tag removed - does not match '
536 536 b'Differential history\n'
537 537 )
538 538 % drev
539 539 )
540 540 continue
541 541
542 542 # Find the last node using Phabricator metadata, and make sure it
543 543 # exists in the repo
544 544 oldnode = lastdiff = None
545 545 if diffs:
546 546 lastdiff = max(diffs, key=lambda d: int(d[b'id']))
547 547 oldnodes = getnodes(lastdiff, precset)
548 548
549 549 _debug(
550 550 unfi.ui,
551 551 b"%s mapped to old nodes %s\n"
552 552 % (
553 553 short(newnode),
554 554 stringutil.pprint([short(n) for n in sorted(oldnodes)]),
555 555 ),
556 556 )
557 557
558 558 # If this commit was the result of `hg fold` after submission,
559 559 # and now resubmitted with --fold, the easiest thing to do is
560 560 # to leave the node clear. This only results in creating a new
561 561 # diff for the _same_ Differential Revision if this commit is
562 562 # the first or last in the selected range. If we picked a node
563 563 # from the list instead, it would have to be the lowest if at
564 564 # the beginning of the --fold range, or the highest at the end.
565 565 # Otherwise, one or more of the nodes wouldn't be considered in
566 566 # the diff, and the Differential wouldn't be properly updated.
567 567 # If this commit is the result of `hg split` in the same
568 568 # scenario, there is a single oldnode here (and multiple
569 569 # newnodes mapped to it). That makes it the same as the normal
570 570 # case, as the edges of the newnode range cleanly maps to one
571 571 # oldnode each.
572 572 if len(oldnodes) == 1:
573 573 oldnode = oldnodes[0]
574 574 if oldnode and not has_node(oldnode):
575 575 oldnode = None
576 576
577 577 result[newnode] = (oldnode, lastdiff, drev)
578 578
579 579 return result
580 580
581 581
582 582 def getdrevmap(repo, revs):
583 583 """Return a dict mapping each rev in `revs` to their Differential Revision
584 584 ID or None.
585 585 """
586 586 result = {}
587 587 for rev in revs:
588 588 result[rev] = None
589 589 ctx = repo[rev]
590 590 # Check commit message
591 591 m = _differentialrevisiondescre.search(ctx.description())
592 592 if m:
593 593 result[rev] = int(m.group('id'))
594 594 continue
595 595 # Check tags
596 596 for tag in repo.nodetags(ctx.node()):
597 597 m = _differentialrevisiontagre.match(tag)
598 598 if m:
599 599 result[rev] = int(m.group(1))
600 600 break
601 601
602 602 return result
603 603
604 604
605 605 def getdiff(basectx, ctx, diffopts):
606 606 """plain-text diff without header (user, commit message, etc)"""
607 607 output = util.stringio()
608 608 for chunk, _label in patch.diffui(
609 609 ctx.repo(), basectx.p1().node(), ctx.node(), None, opts=diffopts
610 610 ):
611 611 output.write(chunk)
612 612 return output.getvalue()
613 613
614 614
615 615 class DiffChangeType(object):
616 616 ADD = 1
617 617 CHANGE = 2
618 618 DELETE = 3
619 619 MOVE_AWAY = 4
620 620 COPY_AWAY = 5
621 621 MOVE_HERE = 6
622 622 COPY_HERE = 7
623 623 MULTICOPY = 8
624 624
625 625
626 626 class DiffFileType(object):
627 627 TEXT = 1
628 628 IMAGE = 2
629 629 BINARY = 3
630 630
631 631
632 632 @attr.s
633 633 class phabhunk(dict):
634 634 """Represents a Differential hunk, which is owned by a Differential change
635 635 """
636 636
637 637 oldOffset = attr.ib(default=0) # camelcase-required
638 638 oldLength = attr.ib(default=0) # camelcase-required
639 639 newOffset = attr.ib(default=0) # camelcase-required
640 640 newLength = attr.ib(default=0) # camelcase-required
641 641 corpus = attr.ib(default='')
642 642 # These get added to the phabchange's equivalents
643 643 addLines = attr.ib(default=0) # camelcase-required
644 644 delLines = attr.ib(default=0) # camelcase-required
645 645
646 646
647 647 @attr.s
648 648 class phabchange(object):
649 649 """Represents a Differential change, owns Differential hunks and owned by a
650 650 Differential diff. Each one represents one file in a diff.
651 651 """
652 652
653 653 currentPath = attr.ib(default=None) # camelcase-required
654 654 oldPath = attr.ib(default=None) # camelcase-required
655 655 awayPaths = attr.ib(default=attr.Factory(list)) # camelcase-required
656 656 metadata = attr.ib(default=attr.Factory(dict))
657 657 oldProperties = attr.ib(default=attr.Factory(dict)) # camelcase-required
658 658 newProperties = attr.ib(default=attr.Factory(dict)) # camelcase-required
659 659 type = attr.ib(default=DiffChangeType.CHANGE)
660 660 fileType = attr.ib(default=DiffFileType.TEXT) # camelcase-required
661 661 commitHash = attr.ib(default=None) # camelcase-required
662 662 addLines = attr.ib(default=0) # camelcase-required
663 663 delLines = attr.ib(default=0) # camelcase-required
664 664 hunks = attr.ib(default=attr.Factory(list))
665 665
666 666 def copynewmetadatatoold(self):
667 667 for key in list(self.metadata.keys()):
668 668 newkey = key.replace(b'new:', b'old:')
669 669 self.metadata[newkey] = self.metadata[key]
670 670
671 671 def addoldmode(self, value):
672 672 self.oldProperties[b'unix:filemode'] = value
673 673
674 674 def addnewmode(self, value):
675 675 self.newProperties[b'unix:filemode'] = value
676 676
677 677 def addhunk(self, hunk):
678 678 if not isinstance(hunk, phabhunk):
679 679 raise error.Abort(b'phabchange.addhunk only takes phabhunks')
680 680 self.hunks.append(pycompat.byteskwargs(attr.asdict(hunk)))
681 681 # It's useful to include these stats since the Phab web UI shows them,
682 682 # and uses them to estimate how large a change a Revision is. Also used
683 683 # in email subjects for the [+++--] bit.
684 684 self.addLines += hunk.addLines
685 685 self.delLines += hunk.delLines
686 686
687 687
688 688 @attr.s
689 689 class phabdiff(object):
690 690 """Represents a Differential diff, owns Differential changes. Corresponds
691 691 to a commit.
692 692 """
693 693
694 694 # Doesn't seem to be any reason to send this (output of uname -n)
695 695 sourceMachine = attr.ib(default=b'') # camelcase-required
696 696 sourcePath = attr.ib(default=b'/') # camelcase-required
697 697 sourceControlBaseRevision = attr.ib(default=b'0' * 40) # camelcase-required
698 698 sourceControlPath = attr.ib(default=b'/') # camelcase-required
699 699 sourceControlSystem = attr.ib(default=b'hg') # camelcase-required
700 700 branch = attr.ib(default=b'default')
701 701 bookmark = attr.ib(default=None)
702 702 creationMethod = attr.ib(default=b'phabsend') # camelcase-required
703 703 lintStatus = attr.ib(default=b'none') # camelcase-required
704 704 unitStatus = attr.ib(default=b'none') # camelcase-required
705 705 changes = attr.ib(default=attr.Factory(dict))
706 706 repositoryPHID = attr.ib(default=None) # camelcase-required
707 707
708 708 def addchange(self, change):
709 709 if not isinstance(change, phabchange):
710 710 raise error.Abort(b'phabdiff.addchange only takes phabchanges')
711 711 self.changes[change.currentPath] = pycompat.byteskwargs(
712 712 attr.asdict(change)
713 713 )
714 714
715 715
716 716 def maketext(pchange, basectx, ctx, fname):
717 717 """populate the phabchange for a text file"""
718 718 repo = ctx.repo()
719 719 fmatcher = match.exact([fname])
720 720 diffopts = mdiff.diffopts(git=True, context=32767)
721 721 _pfctx, _fctx, header, fhunks = next(
722 722 patch.diffhunks(repo, basectx.p1(), ctx, fmatcher, opts=diffopts)
723 723 )
724 724
725 725 for fhunk in fhunks:
726 726 (oldOffset, oldLength, newOffset, newLength), lines = fhunk
727 727 corpus = b''.join(lines[1:])
728 728 shunk = list(header)
729 729 shunk.extend(lines)
730 730 _mf, _mt, addLines, delLines, _hb = patch.diffstatsum(
731 731 patch.diffstatdata(util.iterlines(shunk))
732 732 )
733 733 pchange.addhunk(
734 734 phabhunk(
735 735 oldOffset,
736 736 oldLength,
737 737 newOffset,
738 738 newLength,
739 739 corpus,
740 740 addLines,
741 741 delLines,
742 742 )
743 743 )
744 744
745 745
746 746 def uploadchunks(fctx, fphid):
747 747 """upload large binary files as separate chunks.
748 748 Phab requests chunking over 8MiB, and splits into 4MiB chunks
749 749 """
750 750 ui = fctx.repo().ui
751 751 chunks = callconduit(ui, b'file.querychunks', {b'filePHID': fphid})
752 752 with ui.makeprogress(
753 753 _(b'uploading file chunks'), unit=_(b'chunks'), total=len(chunks)
754 754 ) as progress:
755 755 for chunk in chunks:
756 756 progress.increment()
757 757 if chunk[b'complete']:
758 758 continue
759 759 bstart = int(chunk[b'byteStart'])
760 760 bend = int(chunk[b'byteEnd'])
761 761 callconduit(
762 762 ui,
763 763 b'file.uploadchunk',
764 764 {
765 765 b'filePHID': fphid,
766 766 b'byteStart': bstart,
767 767 b'data': base64.b64encode(fctx.data()[bstart:bend]),
768 768 b'dataEncoding': b'base64',
769 769 },
770 770 )
771 771
772 772
773 773 def uploadfile(fctx):
774 774 """upload binary files to Phabricator"""
775 775 repo = fctx.repo()
776 776 ui = repo.ui
777 777 fname = fctx.path()
778 778 size = fctx.size()
779 779 fhash = pycompat.bytestr(hashlib.sha256(fctx.data()).hexdigest())
780 780
781 781 # an allocate call is required first to see if an upload is even required
782 782 # (Phab might already have it) and to determine if chunking is needed
783 783 allocateparams = {
784 784 b'name': fname,
785 785 b'contentLength': size,
786 786 b'contentHash': fhash,
787 787 }
788 788 filealloc = callconduit(ui, b'file.allocate', allocateparams)
789 789 fphid = filealloc[b'filePHID']
790 790
791 791 if filealloc[b'upload']:
792 792 ui.write(_(b'uploading %s\n') % bytes(fctx))
793 793 if not fphid:
794 794 uploadparams = {
795 795 b'name': fname,
796 796 b'data_base64': base64.b64encode(fctx.data()),
797 797 }
798 798 fphid = callconduit(ui, b'file.upload', uploadparams)
799 799 else:
800 800 uploadchunks(fctx, fphid)
801 801 else:
802 802 ui.debug(b'server already has %s\n' % bytes(fctx))
803 803
804 804 if not fphid:
805 805 raise error.Abort(b'Upload of %s failed.' % bytes(fctx))
806 806
807 807 return fphid
808 808
809 809
810 810 def addoldbinary(pchange, oldfctx, fctx):
811 811 """add the metadata for the previous version of a binary file to the
812 812 phabchange for the new version
813 813
814 814 ``oldfctx`` is the previous version of the file; ``fctx`` is the new
815 815 version of the file, or None if the file is being removed.
816 816 """
817 817 if not fctx or fctx.cmp(oldfctx):
818 818 # Files differ, add the old one
819 819 pchange.metadata[b'old:file:size'] = oldfctx.size()
820 820 mimeguess, _enc = mimetypes.guess_type(
821 821 encoding.unifromlocal(oldfctx.path())
822 822 )
823 823 if mimeguess:
824 824 pchange.metadata[b'old:file:mime-type'] = pycompat.bytestr(
825 825 mimeguess
826 826 )
827 827 fphid = uploadfile(oldfctx)
828 828 pchange.metadata[b'old:binary-phid'] = fphid
829 829 else:
830 830 # If it's left as IMAGE/BINARY web UI might try to display it
831 831 pchange.fileType = DiffFileType.TEXT
832 832 pchange.copynewmetadatatoold()
833 833
834 834
835 835 def makebinary(pchange, fctx):
836 836 """populate the phabchange for a binary file"""
837 837 pchange.fileType = DiffFileType.BINARY
838 838 fphid = uploadfile(fctx)
839 839 pchange.metadata[b'new:binary-phid'] = fphid
840 840 pchange.metadata[b'new:file:size'] = fctx.size()
841 841 mimeguess, _enc = mimetypes.guess_type(encoding.unifromlocal(fctx.path()))
842 842 if mimeguess:
843 843 mimeguess = pycompat.bytestr(mimeguess)
844 844 pchange.metadata[b'new:file:mime-type'] = mimeguess
845 845 if mimeguess.startswith(b'image/'):
846 846 pchange.fileType = DiffFileType.IMAGE
847 847
848 848
849 849 # Copied from mercurial/patch.py
850 850 gitmode = {b'l': b'120000', b'x': b'100755', b'': b'100644'}
851 851
852 852
853 853 def notutf8(fctx):
854 854 """detect non-UTF-8 text files since Phabricator requires them to be marked
855 855 as binary
856 856 """
857 857 try:
858 858 fctx.data().decode('utf-8')
859 859 return False
860 860 except UnicodeDecodeError:
861 861 fctx.repo().ui.write(
862 862 _(b'file %s detected as non-UTF-8, marked as binary\n')
863 863 % fctx.path()
864 864 )
865 865 return True
866 866
867 867
868 868 def addremoved(pdiff, basectx, ctx, removed):
869 869 """add removed files to the phabdiff. Shouldn't include moves"""
870 870 for fname in removed:
871 871 pchange = phabchange(
872 872 currentPath=fname, oldPath=fname, type=DiffChangeType.DELETE
873 873 )
874 874 oldfctx = basectx.p1()[fname]
875 875 pchange.addoldmode(gitmode[oldfctx.flags()])
876 876 if not (oldfctx.isbinary() or notutf8(oldfctx)):
877 877 maketext(pchange, basectx, ctx, fname)
878 878
879 879 pdiff.addchange(pchange)
880 880
881 881
882 882 def addmodified(pdiff, basectx, ctx, modified):
883 883 """add modified files to the phabdiff"""
884 884 for fname in modified:
885 885 fctx = ctx[fname]
886 886 oldfctx = basectx.p1()[fname]
887 887 pchange = phabchange(currentPath=fname, oldPath=fname)
888 888 filemode = gitmode[fctx.flags()]
889 889 originalmode = gitmode[oldfctx.flags()]
890 890 if filemode != originalmode:
891 891 pchange.addoldmode(originalmode)
892 892 pchange.addnewmode(filemode)
893 893
894 894 if (
895 895 fctx.isbinary()
896 896 or notutf8(fctx)
897 897 or oldfctx.isbinary()
898 898 or notutf8(oldfctx)
899 899 ):
900 900 makebinary(pchange, fctx)
901 901 addoldbinary(pchange, oldfctx, fctx)
902 902 else:
903 903 maketext(pchange, basectx, ctx, fname)
904 904
905 905 pdiff.addchange(pchange)
906 906
907 907
908 908 def addadded(pdiff, basectx, ctx, added, removed):
909 909 """add file adds to the phabdiff, both new files and copies/moves"""
910 910 # Keep track of files that've been recorded as moved/copied, so if there are
911 911 # additional copies we can mark them (moves get removed from removed)
912 912 copiedchanges = {}
913 913 movedchanges = {}
914 914
915 915 copy = {}
916 916 if basectx != ctx:
917 917 copy = copies.pathcopies(basectx.p1(), ctx)
918 918
919 919 for fname in added:
920 920 fctx = ctx[fname]
921 921 oldfctx = None
922 922 pchange = phabchange(currentPath=fname)
923 923
924 924 filemode = gitmode[fctx.flags()]
925 925
926 926 if copy:
927 927 originalfname = copy.get(fname, fname)
928 928 else:
929 929 originalfname = fname
930 930 if fctx.renamed():
931 931 originalfname = fctx.renamed()[0]
932 932
933 933 renamed = fname != originalfname
934 934
935 935 if renamed:
936 936 oldfctx = basectx.p1()[originalfname]
937 937 originalmode = gitmode[oldfctx.flags()]
938 938 pchange.oldPath = originalfname
939 939
940 940 if originalfname in removed:
941 941 origpchange = phabchange(
942 942 currentPath=originalfname,
943 943 oldPath=originalfname,
944 944 type=DiffChangeType.MOVE_AWAY,
945 945 awayPaths=[fname],
946 946 )
947 947 movedchanges[originalfname] = origpchange
948 948 removed.remove(originalfname)
949 949 pchange.type = DiffChangeType.MOVE_HERE
950 950 elif originalfname in movedchanges:
951 951 movedchanges[originalfname].type = DiffChangeType.MULTICOPY
952 952 movedchanges[originalfname].awayPaths.append(fname)
953 953 pchange.type = DiffChangeType.COPY_HERE
954 954 else: # pure copy
955 955 if originalfname not in copiedchanges:
956 956 origpchange = phabchange(
957 957 currentPath=originalfname, type=DiffChangeType.COPY_AWAY
958 958 )
959 959 copiedchanges[originalfname] = origpchange
960 960 else:
961 961 origpchange = copiedchanges[originalfname]
962 962 origpchange.awayPaths.append(fname)
963 963 pchange.type = DiffChangeType.COPY_HERE
964 964
965 965 if filemode != originalmode:
966 966 pchange.addoldmode(originalmode)
967 967 pchange.addnewmode(filemode)
968 968 else: # Brand-new file
969 969 pchange.addnewmode(gitmode[fctx.flags()])
970 970 pchange.type = DiffChangeType.ADD
971 971
972 972 if (
973 973 fctx.isbinary()
974 974 or notutf8(fctx)
975 975 or (oldfctx and (oldfctx.isbinary() or notutf8(oldfctx)))
976 976 ):
977 977 makebinary(pchange, fctx)
978 978 if renamed:
979 979 addoldbinary(pchange, oldfctx, fctx)
980 980 else:
981 981 maketext(pchange, basectx, ctx, fname)
982 982
983 983 pdiff.addchange(pchange)
984 984
985 985 for _path, copiedchange in copiedchanges.items():
986 986 pdiff.addchange(copiedchange)
987 987 for _path, movedchange in movedchanges.items():
988 988 pdiff.addchange(movedchange)
989 989
990 990
991 991 def creatediff(basectx, ctx):
992 992 """create a Differential Diff"""
993 993 repo = ctx.repo()
994 994 repophid = getrepophid(repo)
995 995 # Create a "Differential Diff" via "differential.creatediff" API
996 996 pdiff = phabdiff(
997 997 sourceControlBaseRevision=b'%s' % basectx.p1().hex(),
998 998 branch=b'%s' % ctx.branch(),
999 999 )
1000 1000 modified, added, removed, _d, _u, _i, _c = basectx.p1().status(ctx)
1001 1001 # addadded will remove moved files from removed, so addremoved won't get
1002 1002 # them
1003 1003 addadded(pdiff, basectx, ctx, added, removed)
1004 1004 addmodified(pdiff, basectx, ctx, modified)
1005 1005 addremoved(pdiff, basectx, ctx, removed)
1006 1006 if repophid:
1007 1007 pdiff.repositoryPHID = repophid
1008 1008 diff = callconduit(
1009 1009 repo.ui,
1010 1010 b'differential.creatediff',
1011 1011 pycompat.byteskwargs(attr.asdict(pdiff)),
1012 1012 )
1013 1013 if not diff:
1014 1014 if basectx != ctx:
1015 1015 msg = _(b'cannot create diff for %s::%s') % (basectx, ctx)
1016 1016 else:
1017 1017 msg = _(b'cannot create diff for %s') % ctx
1018 1018 raise error.Abort(msg)
1019 1019 return diff
1020 1020
1021 1021
1022 1022 def writediffproperties(ctxs, diff):
1023 1023 """write metadata to diff so patches could be applied losslessly
1024 1024
1025 1025 ``ctxs`` is the list of commits that created the diff, in ascending order.
1026 1026 The list is generally a single commit, but may be several when using
1027 1027 ``phabsend --fold``.
1028 1028 """
1029 1029 # creatediff returns with a diffid but query returns with an id
1030 1030 diffid = diff.get(b'diffid', diff.get(b'id'))
1031 1031 basectx = ctxs[0]
1032 1032 tipctx = ctxs[-1]
1033 1033
1034 1034 params = {
1035 1035 b'diff_id': diffid,
1036 1036 b'name': b'hg:meta',
1037 1037 b'data': templatefilters.json(
1038 1038 {
1039 1039 b'user': tipctx.user(),
1040 1040 b'date': b'%d %d' % tipctx.date(),
1041 1041 b'branch': tipctx.branch(),
1042 1042 b'node': tipctx.hex(),
1043 1043 b'parent': basectx.p1().hex(),
1044 1044 }
1045 1045 ),
1046 1046 }
1047 1047 callconduit(basectx.repo().ui, b'differential.setdiffproperty', params)
1048 1048
1049 1049 commits = {}
1050 1050 for ctx in ctxs:
1051 1051 commits[ctx.hex()] = {
1052 1052 b'author': stringutil.person(ctx.user()),
1053 1053 b'authorEmail': stringutil.email(ctx.user()),
1054 1054 b'time': int(ctx.date()[0]),
1055 1055 b'commit': ctx.hex(),
1056 1056 b'parents': [ctx.p1().hex()],
1057 1057 b'branch': ctx.branch(),
1058 1058 }
1059 1059 params = {
1060 1060 b'diff_id': diffid,
1061 1061 b'name': b'local:commits',
1062 1062 b'data': templatefilters.json(commits),
1063 1063 }
1064 1064 callconduit(basectx.repo().ui, b'differential.setdiffproperty', params)
1065 1065
1066 1066
1067 1067 def createdifferentialrevision(
1068 1068 ctxs,
1069 1069 revid=None,
1070 1070 parentrevphid=None,
1071 1071 oldbasenode=None,
1072 1072 oldnode=None,
1073 1073 olddiff=None,
1074 1074 actions=None,
1075 1075 comment=None,
1076 1076 ):
1077 1077 """create or update a Differential Revision
1078 1078
1079 1079 If revid is None, create a new Differential Revision, otherwise update
1080 1080 revid. If parentrevphid is not None, set it as a dependency.
1081 1081
1082 1082 If there is a single commit for the new Differential Revision, ``ctxs`` will
1083 1083 be a list of that single context. Otherwise, it is a list that covers the
1084 1084 range of changes for the differential, where ``ctxs[0]`` is the first change
1085 1085 to include and ``ctxs[-1]`` is the last.
1086 1086
1087 1087 If oldnode is not None, check if the patch content (without commit message
1088 1088 and metadata) has changed before creating another diff. For a Revision with
1089 1089 a single commit, ``oldbasenode`` and ``oldnode`` have the same value. For a
1090 1090 Revision covering multiple commits, ``oldbasenode`` corresponds to
1091 1091 ``ctxs[0]`` the previous time this Revision was posted, and ``oldnode``
1092 1092 corresponds to ``ctxs[-1]``.
1093 1093
1094 1094 If actions is not None, they will be appended to the transaction.
1095 1095 """
1096 1096 ctx = ctxs[-1]
1097 1097 basectx = ctxs[0]
1098 1098
1099 1099 repo = ctx.repo()
1100 1100 if oldnode:
1101 1101 diffopts = mdiff.diffopts(git=True, context=32767)
1102 1102 unfi = repo.unfiltered()
1103 1103 oldctx = unfi[oldnode]
1104 1104 oldbasectx = unfi[oldbasenode]
1105 1105 neednewdiff = getdiff(basectx, ctx, diffopts) != getdiff(
1106 1106 oldbasectx, oldctx, diffopts
1107 1107 )
1108 1108 else:
1109 1109 neednewdiff = True
1110 1110
1111 1111 transactions = []
1112 1112 if neednewdiff:
1113 1113 diff = creatediff(basectx, ctx)
1114 1114 transactions.append({b'type': b'update', b'value': diff[b'phid']})
1115 1115 if comment:
1116 1116 transactions.append({b'type': b'comment', b'value': comment})
1117 1117 else:
1118 1118 # Even if we don't need to upload a new diff because the patch content
1119 1119 # does not change. We might still need to update its metadata so
1120 1120 # pushers could know the correct node metadata.
1121 1121 assert olddiff
1122 1122 diff = olddiff
1123 1123 writediffproperties(ctxs, diff)
1124 1124
1125 1125 # Set the parent Revision every time, so commit re-ordering is picked-up
1126 1126 if parentrevphid:
1127 1127 transactions.append(
1128 1128 {b'type': b'parents.set', b'value': [parentrevphid]}
1129 1129 )
1130 1130
1131 1131 if actions:
1132 1132 transactions += actions
1133 1133
1134 1134 # When folding multiple local commits into a single review, arcanist will
1135 1135 # take the summary line of the first commit as the title, and then
1136 1136 # concatenate the rest of the remaining messages (including each of their
1137 1137 # first lines) to the rest of the first commit message (each separated by
1138 1138 # an empty line), and use that as the summary field. Do the same here.
1139 1139 # For commits with only a one line message, there is no summary field, as
1140 1140 # this gets assigned to the title.
1141 1141 fields = util.sortdict() # sorted for stable wire protocol in tests
1142 1142
1143 1143 for i, _ctx in enumerate(ctxs):
1144 1144 # Parse commit message and update related fields.
1145 1145 desc = _ctx.description()
1146 1146 info = callconduit(
1147 1147 repo.ui, b'differential.parsecommitmessage', {b'corpus': desc}
1148 1148 )
1149 1149
1150 1150 for k in [b'title', b'summary', b'testPlan']:
1151 1151 v = info[b'fields'].get(k)
1152 1152 if not v:
1153 1153 continue
1154 1154
1155 1155 if i == 0:
1156 1156 # Title, summary and test plan (if present) are taken verbatim
1157 1157 # for the first commit.
1158 1158 fields[k] = v.rstrip()
1159 1159 continue
1160 1160 elif k == b'title':
1161 1161 # Add subsequent titles (i.e. the first line of the commit
1162 1162 # message) back to the summary.
1163 1163 k = b'summary'
1164 1164
1165 1165 # Append any current field to the existing composite field
1166 1166 fields[k] = b'\n\n'.join(filter(None, [fields.get(k), v.rstrip()]))
1167 1167
1168 1168 for k, v in fields.items():
1169 1169 transactions.append({b'type': k, b'value': v})
1170 1170
1171 1171 params = {b'transactions': transactions}
1172 1172 if revid is not None:
1173 1173 # Update an existing Differential Revision
1174 1174 params[b'objectIdentifier'] = revid
1175 1175
1176 1176 revision = callconduit(repo.ui, b'differential.revision.edit', params)
1177 1177 if not revision:
1178 1178 if len(ctxs) == 1:
1179 1179 msg = _(b'cannot create revision for %s') % ctx
1180 1180 else:
1181 1181 msg = _(b'cannot create revision for %s::%s') % (basectx, ctx)
1182 1182 raise error.Abort(msg)
1183 1183
1184 1184 return revision, diff
1185 1185
1186 1186
1187 1187 def userphids(ui, names):
1188 1188 """convert user names to PHIDs"""
1189 1189 names = [name.lower() for name in names]
1190 1190 query = {b'constraints': {b'usernames': names}}
1191 1191 result = callconduit(ui, b'user.search', query)
1192 1192 # username not found is not an error of the API. So check if we have missed
1193 1193 # some names here.
1194 1194 data = result[b'data']
1195 1195 resolved = {entry[b'fields'][b'username'].lower() for entry in data}
1196 1196 unresolved = set(names) - resolved
1197 1197 if unresolved:
1198 1198 raise error.Abort(
1199 1199 _(b'unknown username: %s') % b' '.join(sorted(unresolved))
1200 1200 )
1201 1201 return [entry[b'phid'] for entry in data]
1202 1202
1203 1203
1204 1204 def _print_phabsend_action(ui, ctx, newrevid, action):
1205 1205 """print the ``action`` that occurred when posting ``ctx`` for review
1206 1206
1207 1207 This is a utility function for the sending phase of ``phabsend``, which
1208 1208 makes it easier to show a status for all local commits with `--fold``.
1209 1209 """
1210 1210 actiondesc = ui.label(
1211 1211 {
1212 1212 b'created': _(b'created'),
1213 1213 b'skipped': _(b'skipped'),
1214 1214 b'updated': _(b'updated'),
1215 1215 }[action],
1216 1216 b'phabricator.action.%s' % action,
1217 1217 )
1218 1218 drevdesc = ui.label(b'D%d' % newrevid, b'phabricator.drev')
1219 1219 nodedesc = ui.label(bytes(ctx), b'phabricator.node')
1220 1220 desc = ui.label(ctx.description().split(b'\n')[0], b'phabricator.desc')
1221 1221 ui.write(_(b'%s - %s - %s: %s\n') % (drevdesc, actiondesc, nodedesc, desc))
1222 1222
1223 1223
1224 1224 def _amend_diff_properties(unfi, drevid, newnodes, diff):
1225 1225 """update the local commit list for the ``diff`` associated with ``drevid``
1226 1226
1227 1227 This is a utility function for the amend phase of ``phabsend``, which
1228 1228 converts failures to warning messages.
1229 1229 """
1230 1230 _debug(
1231 1231 unfi.ui,
1232 1232 b"new commits: %s\n" % stringutil.pprint([short(n) for n in newnodes]),
1233 1233 )
1234 1234
1235 1235 try:
1236 1236 writediffproperties([unfi[newnode] for newnode in newnodes], diff)
1237 1237 except util.urlerr.urlerror:
1238 1238 # If it fails just warn and keep going, otherwise the DREV
1239 1239 # associations will be lost
1240 1240 unfi.ui.warnnoi18n(b'Failed to update metadata for D%d\n' % drevid)
1241 1241
1242 1242
1243 1243 @vcrcommand(
1244 1244 b'phabsend',
1245 1245 [
1246 1246 (b'r', b'rev', [], _(b'revisions to send'), _(b'REV')),
1247 1247 (b'', b'amend', True, _(b'update commit messages')),
1248 1248 (b'', b'reviewer', [], _(b'specify reviewers')),
1249 1249 (b'', b'blocker', [], _(b'specify blocking reviewers')),
1250 1250 (
1251 1251 b'm',
1252 1252 b'comment',
1253 1253 b'',
1254 1254 _(b'add a comment to Revisions with new/updated Diffs'),
1255 1255 ),
1256 1256 (b'', b'confirm', None, _(b'ask for confirmation before sending')),
1257 1257 (b'', b'fold', False, _(b'combine the revisions into one review')),
1258 1258 ],
1259 1259 _(b'REV [OPTIONS]'),
1260 1260 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1261 1261 )
1262 1262 def phabsend(ui, repo, *revs, **opts):
1263 1263 """upload changesets to Phabricator
1264 1264
1265 1265 If there are multiple revisions specified, they will be send as a stack
1266 1266 with a linear dependencies relationship using the order specified by the
1267 1267 revset.
1268 1268
1269 1269 For the first time uploading changesets, local tags will be created to
1270 1270 maintain the association. After the first time, phabsend will check
1271 1271 obsstore and tags information so it can figure out whether to update an
1272 1272 existing Differential Revision, or create a new one.
1273 1273
1274 1274 If --amend is set, update commit messages so they have the
1275 1275 ``Differential Revision`` URL, remove related tags. This is similar to what
1276 1276 arcanist will do, and is more desired in author-push workflows. Otherwise,
1277 1277 use local tags to record the ``Differential Revision`` association.
1278 1278
1279 1279 The --confirm option lets you confirm changesets before sending them. You
1280 1280 can also add following to your configuration file to make it default
1281 1281 behaviour::
1282 1282
1283 1283 [phabsend]
1284 1284 confirm = true
1285 1285
1286 1286 By default, a separate review will be created for each commit that is
1287 1287 selected, and will have the same parent/child relationship in Phabricator.
1288 1288 If ``--fold`` is set, multiple commits are rolled up into a single review
1289 1289 as if diffed from the parent of the first revision to the last. The commit
1290 1290 messages are concatenated in the summary field on Phabricator.
1291 1291
1292 1292 phabsend will check obsstore and the above association to decide whether to
1293 1293 update an existing Differential Revision, or create a new one.
1294 1294 """
1295 1295 opts = pycompat.byteskwargs(opts)
1296 1296 revs = list(revs) + opts.get(b'rev', [])
1297 1297 revs = scmutil.revrange(repo, revs)
1298 1298 revs.sort() # ascending order to preserve topological parent/child in phab
1299 1299
1300 1300 if not revs:
1301 1301 raise error.Abort(_(b'phabsend requires at least one changeset'))
1302 1302 if opts.get(b'amend'):
1303 1303 cmdutil.checkunfinished(repo)
1304 1304
1305 1305 ctxs = [repo[rev] for rev in revs]
1306 1306
1307 1307 if any(c for c in ctxs if c.obsolete()):
1308 1308 raise error.Abort(_(b"obsolete commits cannot be posted for review"))
1309 1309
1310 # Ensure the local commits are an unbroken range. The semantics of the
1311 # --fold option implies this, and the auto restacking of orphans requires
1312 # it. Otherwise A+C in A->B->C will cause B to be orphaned, and C' to
1313 # get A' as a parent.
1314 def _fail_nonlinear_revs(revs, skiprev, revtype):
1315 badnodes = [repo[r].node() for r in revs if r != skiprev]
1316 raise error.Abort(
1317 _(b"cannot phabsend multiple %s revisions: %s")
1318 % (revtype, scmutil.nodesummaries(repo, badnodes)),
1319 hint=_(b"the revisions must form a linear chain"),
1320 )
1321
1322 heads = repo.revs(b'heads(%ld)', revs)
1323 if len(heads) > 1:
1324 _fail_nonlinear_revs(heads, heads.max(), b"head")
1325
1326 roots = repo.revs(b'roots(%ld)', revs)
1327 if len(roots) > 1:
1328 _fail_nonlinear_revs(roots, roots.min(), b"root")
1329
1310 1330 fold = opts.get(b'fold')
1311 1331 if fold:
1312 1332 if len(revs) == 1:
1313 1333 # TODO: just switch to --no-fold instead?
1314 1334 raise error.Abort(_(b"cannot fold a single revision"))
1315 1335
1316 1336 # There's no clear way to manage multiple commits with a Dxxx tag, so
1317 1337 # require the amend option. (We could append "_nnn", but then it
1318 1338 # becomes jumbled if earlier commits are added to an update.) It should
1319 1339 # lock the repo and ensure that the range is editable, but that would
1320 1340 # make the code pretty convoluted. The default behavior of `arc` is to
1321 1341 # create a new review anyway.
1322 1342 if not opts.get(b"amend"):
1323 1343 raise error.Abort(_(b"cannot fold with --no-amend"))
1324 1344
1325 # Ensure the local commits are an unbroken range
1326 revrange = repo.revs(b'(first(%ld)::last(%ld))', revs, revs)
1327 if any(r for r in revs if r not in revrange) or any(
1328 r for r in revrange if r not in revs
1329 ):
1330 raise error.Abort(_(b"cannot fold non-linear revisions"))
1331
1332 1345 # It might be possible to bucketize the revisions by the DREV value, and
1333 1346 # iterate over those groups when posting, and then again when amending.
1334 1347 # But for simplicity, require all selected revisions to be for the same
1335 1348 # DREV (if present). Adding local revisions to an existing DREV is
1336 1349 # acceptable.
1337 1350 drevmatchers = [
1338 1351 _differentialrevisiondescre.search(ctx.description())
1339 1352 for ctx in ctxs
1340 1353 ]
1341 1354 if len({m.group('url') for m in drevmatchers if m}) > 1:
1342 1355 raise error.Abort(
1343 1356 _(b"cannot fold revisions with different DREV values")
1344 1357 )
1345 1358
1346 1359 # {newnode: (oldnode, olddiff, olddrev}
1347 1360 oldmap = getoldnodedrevmap(repo, [repo[r].node() for r in revs])
1348 1361
1349 1362 confirm = ui.configbool(b'phabsend', b'confirm')
1350 1363 confirm |= bool(opts.get(b'confirm'))
1351 1364 if confirm:
1352 1365 confirmed = _confirmbeforesend(repo, revs, oldmap)
1353 1366 if not confirmed:
1354 1367 raise error.Abort(_(b'phabsend cancelled'))
1355 1368
1356 1369 actions = []
1357 1370 reviewers = opts.get(b'reviewer', [])
1358 1371 blockers = opts.get(b'blocker', [])
1359 1372 phids = []
1360 1373 if reviewers:
1361 1374 phids.extend(userphids(repo.ui, reviewers))
1362 1375 if blockers:
1363 1376 phids.extend(
1364 1377 map(
1365 1378 lambda phid: b'blocking(%s)' % phid,
1366 1379 userphids(repo.ui, blockers),
1367 1380 )
1368 1381 )
1369 1382 if phids:
1370 1383 actions.append({b'type': b'reviewers.add', b'value': phids})
1371 1384
1372 1385 drevids = [] # [int]
1373 1386 diffmap = {} # {newnode: diff}
1374 1387
1375 1388 # Send patches one by one so we know their Differential Revision PHIDs and
1376 1389 # can provide dependency relationship
1377 1390 lastrevphid = None
1378 1391 for ctx in ctxs:
1379 1392 if fold:
1380 1393 ui.debug(b'sending rev %d::%d\n' % (ctx.rev(), ctxs[-1].rev()))
1381 1394 else:
1382 1395 ui.debug(b'sending rev %d\n' % ctx.rev())
1383 1396
1384 1397 # Get Differential Revision ID
1385 1398 oldnode, olddiff, revid = oldmap.get(ctx.node(), (None, None, None))
1386 1399 oldbasenode, oldbasediff, oldbaserevid = oldnode, olddiff, revid
1387 1400
1388 1401 if fold:
1389 1402 oldbasenode, oldbasediff, oldbaserevid = oldmap.get(
1390 1403 ctxs[-1].node(), (None, None, None)
1391 1404 )
1392 1405
1393 1406 if oldnode != ctx.node() or opts.get(b'amend'):
1394 1407 # Create or update Differential Revision
1395 1408 revision, diff = createdifferentialrevision(
1396 1409 ctxs if fold else [ctx],
1397 1410 revid,
1398 1411 lastrevphid,
1399 1412 oldbasenode,
1400 1413 oldnode,
1401 1414 olddiff,
1402 1415 actions,
1403 1416 opts.get(b'comment'),
1404 1417 )
1405 1418
1406 1419 if fold:
1407 1420 for ctx in ctxs:
1408 1421 diffmap[ctx.node()] = diff
1409 1422 else:
1410 1423 diffmap[ctx.node()] = diff
1411 1424
1412 1425 newrevid = int(revision[b'object'][b'id'])
1413 1426 newrevphid = revision[b'object'][b'phid']
1414 1427 if revid:
1415 1428 action = b'updated'
1416 1429 else:
1417 1430 action = b'created'
1418 1431
1419 1432 # Create a local tag to note the association, if commit message
1420 1433 # does not have it already
1421 1434 if not fold:
1422 1435 m = _differentialrevisiondescre.search(ctx.description())
1423 1436 if not m or int(m.group('id')) != newrevid:
1424 1437 tagname = b'D%d' % newrevid
1425 1438 tags.tag(
1426 1439 repo,
1427 1440 tagname,
1428 1441 ctx.node(),
1429 1442 message=None,
1430 1443 user=None,
1431 1444 date=None,
1432 1445 local=True,
1433 1446 )
1434 1447 else:
1435 1448 # Nothing changed. But still set "newrevphid" so the next revision
1436 1449 # could depend on this one and "newrevid" for the summary line.
1437 1450 newrevphid = querydrev(repo.ui, b'%d' % revid)[0][b'phid']
1438 1451 newrevid = revid
1439 1452 action = b'skipped'
1440 1453
1441 1454 drevids.append(newrevid)
1442 1455 lastrevphid = newrevphid
1443 1456
1444 1457 if fold:
1445 1458 for c in ctxs:
1446 1459 if oldmap.get(c.node(), (None, None, None))[2]:
1447 1460 action = b'updated'
1448 1461 else:
1449 1462 action = b'created'
1450 1463 _print_phabsend_action(ui, c, newrevid, action)
1451 1464 break
1452 1465
1453 1466 _print_phabsend_action(ui, ctx, newrevid, action)
1454 1467
1455 1468 # Update commit messages and remove tags
1456 1469 if opts.get(b'amend'):
1457 1470 unfi = repo.unfiltered()
1458 1471 drevs = callconduit(ui, b'differential.query', {b'ids': drevids})
1459 1472 with repo.wlock(), repo.lock(), repo.transaction(b'phabsend'):
1460 1473 # Eagerly evaluate commits to restabilize before creating new
1461 1474 # commits. The selected revisions are excluded because they are
1462 1475 # automatically restacked as part of the submission process.
1463 1476 restack = [
1464 1477 c
1465 1478 for c in repo.set(
1466 1479 b"(%ld::) - (%ld) - unstable() - obsolete() - public()",
1467 1480 revs,
1468 1481 revs,
1469 1482 )
1470 1483 ]
1471 1484 wnode = unfi[b'.'].node()
1472 1485 mapping = {} # {oldnode: [newnode]}
1473 1486 newnodes = []
1474 1487
1475 1488 drevid = drevids[0]
1476 1489
1477 1490 for i, rev in enumerate(revs):
1478 1491 old = unfi[rev]
1479 1492 if not fold:
1480 1493 drevid = drevids[i]
1481 1494 drev = [d for d in drevs if int(d[b'id']) == drevid][0]
1482 1495
1483 1496 newdesc = get_amended_desc(drev, old, fold)
1484 1497 # Make sure commit message contain "Differential Revision"
1485 1498 if (
1486 1499 old.description() != newdesc
1487 1500 or old.p1().node() in mapping
1488 1501 or old.p2().node() in mapping
1489 1502 ):
1490 1503 if old.phase() == phases.public:
1491 1504 ui.warn(
1492 1505 _(b"warning: not updating public commit %s\n")
1493 1506 % scmutil.formatchangeid(old)
1494 1507 )
1495 1508 continue
1496 1509 parents = [
1497 1510 mapping.get(old.p1().node(), (old.p1(),))[0],
1498 1511 mapping.get(old.p2().node(), (old.p2(),))[0],
1499 1512 ]
1500 1513 new = context.metadataonlyctx(
1501 1514 repo,
1502 1515 old,
1503 1516 parents=parents,
1504 1517 text=newdesc,
1505 1518 user=old.user(),
1506 1519 date=old.date(),
1507 1520 extra=old.extra(),
1508 1521 )
1509 1522
1510 1523 newnode = new.commit()
1511 1524
1512 1525 mapping[old.node()] = [newnode]
1513 1526
1514 1527 if fold:
1515 1528 # Defer updating the (single) Diff until all nodes are
1516 1529 # collected. No tags were created, so none need to be
1517 1530 # removed.
1518 1531 newnodes.append(newnode)
1519 1532 continue
1520 1533
1521 1534 _amend_diff_properties(
1522 1535 unfi, drevid, [newnode], diffmap[old.node()]
1523 1536 )
1524 1537
1525 1538 # Remove local tags since it's no longer necessary
1526 1539 tagname = b'D%d' % drevid
1527 1540 if tagname in repo.tags():
1528 1541 tags.tag(
1529 1542 repo,
1530 1543 tagname,
1531 1544 nullid,
1532 1545 message=None,
1533 1546 user=None,
1534 1547 date=None,
1535 1548 local=True,
1536 1549 )
1537 1550 elif fold:
1538 1551 # When folding multiple commits into one review with
1539 1552 # --fold, track even the commits that weren't amended, so
1540 1553 # that their association isn't lost if the properties are
1541 1554 # rewritten below.
1542 1555 newnodes.append(old.node())
1543 1556
1544 1557 # If the submitted commits are public, no amend takes place so
1545 1558 # there are no newnodes and therefore no diff update to do.
1546 1559 if fold and newnodes:
1547 1560 diff = diffmap[old.node()]
1548 1561
1549 1562 # The diff object in diffmap doesn't have the local commits
1550 1563 # because that could be returned from differential.creatediff,
1551 1564 # not differential.querydiffs. So use the queried diff (if
1552 1565 # present), or force the amend (a new revision is being posted.)
1553 1566 if not olddiff or set(newnodes) != getlocalcommits(olddiff):
1554 1567 _debug(ui, b"updating local commit list for D%d\n" % drevid)
1555 1568 _amend_diff_properties(unfi, drevid, newnodes, diff)
1556 1569 else:
1557 1570 _debug(
1558 1571 ui,
1559 1572 b"local commit list for D%d is already up-to-date\n"
1560 1573 % drevid,
1561 1574 )
1562 1575 elif fold:
1563 1576 _debug(ui, b"no newnodes to update\n")
1564 1577
1565 1578 # Restack any children of first-time submissions that were orphaned
1566 1579 # in the process. The ctx won't report that it is an orphan until
1567 1580 # the cleanup takes place below.
1568 1581 for old in restack:
1569 1582 parents = [
1570 1583 mapping.get(old.p1().node(), (old.p1(),))[0],
1571 1584 mapping.get(old.p2().node(), (old.p2(),))[0],
1572 1585 ]
1573 1586 new = context.metadataonlyctx(
1574 1587 repo,
1575 1588 old,
1576 1589 parents=parents,
1577 1590 text=old.description(),
1578 1591 user=old.user(),
1579 1592 date=old.date(),
1580 1593 extra=old.extra(),
1581 1594 )
1582 1595
1583 1596 newnode = new.commit()
1584 1597
1585 1598 # Don't obsolete unselected descendants of nodes that have not
1586 1599 # been changed in this transaction- that results in an error.
1587 1600 if newnode != old.node():
1588 1601 mapping[old.node()] = [newnode]
1589 1602 _debug(
1590 1603 ui,
1591 1604 b"restabilizing %s as %s\n"
1592 1605 % (short(old.node()), short(newnode)),
1593 1606 )
1594 1607 else:
1595 1608 _debug(
1596 1609 ui,
1597 1610 b"not restabilizing unchanged %s\n" % short(old.node()),
1598 1611 )
1599 1612
1600 1613 scmutil.cleanupnodes(repo, mapping, b'phabsend', fixphase=True)
1601 1614 if wnode in mapping:
1602 1615 unfi.setparents(mapping[wnode][0])
1603 1616
1604 1617
1605 1618 # Map from "hg:meta" keys to header understood by "hg import". The order is
1606 1619 # consistent with "hg export" output.
1607 1620 _metanamemap = util.sortdict(
1608 1621 [
1609 1622 (b'user', b'User'),
1610 1623 (b'date', b'Date'),
1611 1624 (b'branch', b'Branch'),
1612 1625 (b'node', b'Node ID'),
1613 1626 (b'parent', b'Parent '),
1614 1627 ]
1615 1628 )
1616 1629
1617 1630
1618 1631 def _confirmbeforesend(repo, revs, oldmap):
1619 1632 url, token = readurltoken(repo.ui)
1620 1633 ui = repo.ui
1621 1634 for rev in revs:
1622 1635 ctx = repo[rev]
1623 1636 desc = ctx.description().splitlines()[0]
1624 1637 oldnode, olddiff, drevid = oldmap.get(ctx.node(), (None, None, None))
1625 1638 if drevid:
1626 1639 drevdesc = ui.label(b'D%d' % drevid, b'phabricator.drev')
1627 1640 else:
1628 1641 drevdesc = ui.label(_(b'NEW'), b'phabricator.drev')
1629 1642
1630 1643 ui.write(
1631 1644 _(b'%s - %s: %s\n')
1632 1645 % (
1633 1646 drevdesc,
1634 1647 ui.label(bytes(ctx), b'phabricator.node'),
1635 1648 ui.label(desc, b'phabricator.desc'),
1636 1649 )
1637 1650 )
1638 1651
1639 1652 if ui.promptchoice(
1640 1653 _(b'Send the above changes to %s (yn)?$$ &Yes $$ &No') % url
1641 1654 ):
1642 1655 return False
1643 1656
1644 1657 return True
1645 1658
1646 1659
1647 1660 _knownstatusnames = {
1648 1661 b'accepted',
1649 1662 b'needsreview',
1650 1663 b'needsrevision',
1651 1664 b'closed',
1652 1665 b'abandoned',
1653 1666 b'changesplanned',
1654 1667 }
1655 1668
1656 1669
1657 1670 def _getstatusname(drev):
1658 1671 """get normalized status name from a Differential Revision"""
1659 1672 return drev[b'statusName'].replace(b' ', b'').lower()
1660 1673
1661 1674
1662 1675 # Small language to specify differential revisions. Support symbols: (), :X,
1663 1676 # +, and -.
1664 1677
1665 1678 _elements = {
1666 1679 # token-type: binding-strength, primary, prefix, infix, suffix
1667 1680 b'(': (12, None, (b'group', 1, b')'), None, None),
1668 1681 b':': (8, None, (b'ancestors', 8), None, None),
1669 1682 b'&': (5, None, None, (b'and_', 5), None),
1670 1683 b'+': (4, None, None, (b'add', 4), None),
1671 1684 b'-': (4, None, None, (b'sub', 4), None),
1672 1685 b')': (0, None, None, None, None),
1673 1686 b'symbol': (0, b'symbol', None, None, None),
1674 1687 b'end': (0, None, None, None, None),
1675 1688 }
1676 1689
1677 1690
1678 1691 def _tokenize(text):
1679 1692 view = memoryview(text) # zero-copy slice
1680 1693 special = b'():+-& '
1681 1694 pos = 0
1682 1695 length = len(text)
1683 1696 while pos < length:
1684 1697 symbol = b''.join(
1685 1698 itertools.takewhile(
1686 1699 lambda ch: ch not in special, pycompat.iterbytestr(view[pos:])
1687 1700 )
1688 1701 )
1689 1702 if symbol:
1690 1703 yield (b'symbol', symbol, pos)
1691 1704 pos += len(symbol)
1692 1705 else: # special char, ignore space
1693 1706 if text[pos : pos + 1] != b' ':
1694 1707 yield (text[pos : pos + 1], None, pos)
1695 1708 pos += 1
1696 1709 yield (b'end', None, pos)
1697 1710
1698 1711
1699 1712 def _parse(text):
1700 1713 tree, pos = parser.parser(_elements).parse(_tokenize(text))
1701 1714 if pos != len(text):
1702 1715 raise error.ParseError(b'invalid token', pos)
1703 1716 return tree
1704 1717
1705 1718
1706 1719 def _parsedrev(symbol):
1707 1720 """str -> int or None, ex. 'D45' -> 45; '12' -> 12; 'x' -> None"""
1708 1721 if symbol.startswith(b'D') and symbol[1:].isdigit():
1709 1722 return int(symbol[1:])
1710 1723 if symbol.isdigit():
1711 1724 return int(symbol)
1712 1725
1713 1726
1714 1727 def _prefetchdrevs(tree):
1715 1728 """return ({single-drev-id}, {ancestor-drev-id}) to prefetch"""
1716 1729 drevs = set()
1717 1730 ancestordrevs = set()
1718 1731 op = tree[0]
1719 1732 if op == b'symbol':
1720 1733 r = _parsedrev(tree[1])
1721 1734 if r:
1722 1735 drevs.add(r)
1723 1736 elif op == b'ancestors':
1724 1737 r, a = _prefetchdrevs(tree[1])
1725 1738 drevs.update(r)
1726 1739 ancestordrevs.update(r)
1727 1740 ancestordrevs.update(a)
1728 1741 else:
1729 1742 for t in tree[1:]:
1730 1743 r, a = _prefetchdrevs(t)
1731 1744 drevs.update(r)
1732 1745 ancestordrevs.update(a)
1733 1746 return drevs, ancestordrevs
1734 1747
1735 1748
1736 1749 def querydrev(ui, spec):
1737 1750 """return a list of "Differential Revision" dicts
1738 1751
1739 1752 spec is a string using a simple query language, see docstring in phabread
1740 1753 for details.
1741 1754
1742 1755 A "Differential Revision dict" looks like:
1743 1756
1744 1757 {
1745 1758 "activeDiffPHID": "PHID-DIFF-xoqnjkobbm6k4dk6hi72",
1746 1759 "authorPHID": "PHID-USER-tv3ohwc4v4jeu34otlye",
1747 1760 "auxiliary": {
1748 1761 "phabricator:depends-on": [
1749 1762 "PHID-DREV-gbapp366kutjebt7agcd"
1750 1763 ]
1751 1764 "phabricator:projects": [],
1752 1765 },
1753 1766 "branch": "default",
1754 1767 "ccs": [],
1755 1768 "commits": [],
1756 1769 "dateCreated": "1499181406",
1757 1770 "dateModified": "1499182103",
1758 1771 "diffs": [
1759 1772 "3",
1760 1773 "4",
1761 1774 ],
1762 1775 "hashes": [],
1763 1776 "id": "2",
1764 1777 "lineCount": "2",
1765 1778 "phid": "PHID-DREV-672qvysjcczopag46qty",
1766 1779 "properties": {},
1767 1780 "repositoryPHID": "PHID-REPO-hub2hx62ieuqeheznasv",
1768 1781 "reviewers": [],
1769 1782 "sourcePath": null
1770 1783 "status": "0",
1771 1784 "statusName": "Needs Review",
1772 1785 "summary": "",
1773 1786 "testPlan": "",
1774 1787 "title": "example",
1775 1788 "uri": "https://phab.example.com/D2",
1776 1789 }
1777 1790 """
1778 1791 # TODO: replace differential.query and differential.querydiffs with
1779 1792 # differential.diff.search because the former (and their output) are
1780 1793 # frozen, and planned to be deprecated and removed.
1781 1794
1782 1795 def fetch(params):
1783 1796 """params -> single drev or None"""
1784 1797 key = (params.get(b'ids') or params.get(b'phids') or [None])[0]
1785 1798 if key in prefetched:
1786 1799 return prefetched[key]
1787 1800 drevs = callconduit(ui, b'differential.query', params)
1788 1801 # Fill prefetched with the result
1789 1802 for drev in drevs:
1790 1803 prefetched[drev[b'phid']] = drev
1791 1804 prefetched[int(drev[b'id'])] = drev
1792 1805 if key not in prefetched:
1793 1806 raise error.Abort(
1794 1807 _(b'cannot get Differential Revision %r') % params
1795 1808 )
1796 1809 return prefetched[key]
1797 1810
1798 1811 def getstack(topdrevids):
1799 1812 """given a top, get a stack from the bottom, [id] -> [id]"""
1800 1813 visited = set()
1801 1814 result = []
1802 1815 queue = [{b'ids': [i]} for i in topdrevids]
1803 1816 while queue:
1804 1817 params = queue.pop()
1805 1818 drev = fetch(params)
1806 1819 if drev[b'id'] in visited:
1807 1820 continue
1808 1821 visited.add(drev[b'id'])
1809 1822 result.append(int(drev[b'id']))
1810 1823 auxiliary = drev.get(b'auxiliary', {})
1811 1824 depends = auxiliary.get(b'phabricator:depends-on', [])
1812 1825 for phid in depends:
1813 1826 queue.append({b'phids': [phid]})
1814 1827 result.reverse()
1815 1828 return smartset.baseset(result)
1816 1829
1817 1830 # Initialize prefetch cache
1818 1831 prefetched = {} # {id or phid: drev}
1819 1832
1820 1833 tree = _parse(spec)
1821 1834 drevs, ancestordrevs = _prefetchdrevs(tree)
1822 1835
1823 1836 # developer config: phabricator.batchsize
1824 1837 batchsize = ui.configint(b'phabricator', b'batchsize')
1825 1838
1826 1839 # Prefetch Differential Revisions in batch
1827 1840 tofetch = set(drevs)
1828 1841 for r in ancestordrevs:
1829 1842 tofetch.update(range(max(1, r - batchsize), r + 1))
1830 1843 if drevs:
1831 1844 fetch({b'ids': list(tofetch)})
1832 1845 validids = sorted(set(getstack(list(ancestordrevs))) | set(drevs))
1833 1846
1834 1847 # Walk through the tree, return smartsets
1835 1848 def walk(tree):
1836 1849 op = tree[0]
1837 1850 if op == b'symbol':
1838 1851 drev = _parsedrev(tree[1])
1839 1852 if drev:
1840 1853 return smartset.baseset([drev])
1841 1854 elif tree[1] in _knownstatusnames:
1842 1855 drevs = [
1843 1856 r
1844 1857 for r in validids
1845 1858 if _getstatusname(prefetched[r]) == tree[1]
1846 1859 ]
1847 1860 return smartset.baseset(drevs)
1848 1861 else:
1849 1862 raise error.Abort(_(b'unknown symbol: %s') % tree[1])
1850 1863 elif op in {b'and_', b'add', b'sub'}:
1851 1864 assert len(tree) == 3
1852 1865 return getattr(operator, op)(walk(tree[1]), walk(tree[2]))
1853 1866 elif op == b'group':
1854 1867 return walk(tree[1])
1855 1868 elif op == b'ancestors':
1856 1869 return getstack(walk(tree[1]))
1857 1870 else:
1858 1871 raise error.ProgrammingError(b'illegal tree: %r' % tree)
1859 1872
1860 1873 return [prefetched[r] for r in walk(tree)]
1861 1874
1862 1875
1863 1876 def getdescfromdrev(drev):
1864 1877 """get description (commit message) from "Differential Revision"
1865 1878
1866 1879 This is similar to differential.getcommitmessage API. But we only care
1867 1880 about limited fields: title, summary, test plan, and URL.
1868 1881 """
1869 1882 title = drev[b'title']
1870 1883 summary = drev[b'summary'].rstrip()
1871 1884 testplan = drev[b'testPlan'].rstrip()
1872 1885 if testplan:
1873 1886 testplan = b'Test Plan:\n%s' % testplan
1874 1887 uri = b'Differential Revision: %s' % drev[b'uri']
1875 1888 return b'\n\n'.join(filter(None, [title, summary, testplan, uri]))
1876 1889
1877 1890
1878 1891 def get_amended_desc(drev, ctx, folded):
1879 1892 """similar to ``getdescfromdrev``, but supports a folded series of commits
1880 1893
1881 1894 This is used when determining if an individual commit needs to have its
1882 1895 message amended after posting it for review. The determination is made for
1883 1896 each individual commit, even when they were folded into one review.
1884 1897 """
1885 1898 if not folded:
1886 1899 return getdescfromdrev(drev)
1887 1900
1888 1901 uri = b'Differential Revision: %s' % drev[b'uri']
1889 1902
1890 1903 # Since the commit messages were combined when posting multiple commits
1891 1904 # with --fold, the fields can't be read from Phabricator here, or *all*
1892 1905 # affected local revisions will end up with the same commit message after
1893 1906 # the URI is amended in. Append in the DREV line, or update it if it
1894 1907 # exists. At worst, this means commit message or test plan updates on
1895 1908 # Phabricator aren't propagated back to the repository, but that seems
1896 1909 # reasonable for the case where local commits are effectively combined
1897 1910 # in Phabricator.
1898 1911 m = _differentialrevisiondescre.search(ctx.description())
1899 1912 if not m:
1900 1913 return b'\n\n'.join([ctx.description(), uri])
1901 1914
1902 1915 return _differentialrevisiondescre.sub(uri, ctx.description())
1903 1916
1904 1917
1905 1918 def getlocalcommits(diff):
1906 1919 """get the set of local commits from a diff object
1907 1920
1908 1921 See ``getdiffmeta()`` for an example diff object.
1909 1922 """
1910 1923 props = diff.get(b'properties') or {}
1911 1924 commits = props.get(b'local:commits') or {}
1912 1925 if len(commits) > 1:
1913 1926 return {bin(c) for c in commits.keys()}
1914 1927
1915 1928 # Storing the diff metadata predates storing `local:commits`, so continue
1916 1929 # to use that in the --no-fold case.
1917 1930 return {bin(getdiffmeta(diff).get(b'node', b'')) or None}
1918 1931
1919 1932
1920 1933 def getdiffmeta(diff):
1921 1934 """get commit metadata (date, node, user, p1) from a diff object
1922 1935
1923 1936 The metadata could be "hg:meta", sent by phabsend, like:
1924 1937
1925 1938 "properties": {
1926 1939 "hg:meta": {
1927 1940 "branch": "default",
1928 1941 "date": "1499571514 25200",
1929 1942 "node": "98c08acae292b2faf60a279b4189beb6cff1414d",
1930 1943 "user": "Foo Bar <foo@example.com>",
1931 1944 "parent": "6d0abad76b30e4724a37ab8721d630394070fe16"
1932 1945 }
1933 1946 }
1934 1947
1935 1948 Or converted from "local:commits", sent by "arc", like:
1936 1949
1937 1950 "properties": {
1938 1951 "local:commits": {
1939 1952 "98c08acae292b2faf60a279b4189beb6cff1414d": {
1940 1953 "author": "Foo Bar",
1941 1954 "authorEmail": "foo@example.com"
1942 1955 "branch": "default",
1943 1956 "commit": "98c08acae292b2faf60a279b4189beb6cff1414d",
1944 1957 "local": "1000",
1945 1958 "message": "...",
1946 1959 "parents": ["6d0abad76b30e4724a37ab8721d630394070fe16"],
1947 1960 "rev": "98c08acae292b2faf60a279b4189beb6cff1414d",
1948 1961 "summary": "...",
1949 1962 "tag": "",
1950 1963 "time": 1499546314,
1951 1964 }
1952 1965 }
1953 1966 }
1954 1967
1955 1968 Note: metadata extracted from "local:commits" will lose time zone
1956 1969 information.
1957 1970 """
1958 1971 props = diff.get(b'properties') or {}
1959 1972 meta = props.get(b'hg:meta')
1960 1973 if not meta:
1961 1974 if props.get(b'local:commits'):
1962 1975 commit = sorted(props[b'local:commits'].values())[0]
1963 1976 meta = {}
1964 1977 if b'author' in commit and b'authorEmail' in commit:
1965 1978 meta[b'user'] = b'%s <%s>' % (
1966 1979 commit[b'author'],
1967 1980 commit[b'authorEmail'],
1968 1981 )
1969 1982 if b'time' in commit:
1970 1983 meta[b'date'] = b'%d 0' % int(commit[b'time'])
1971 1984 if b'branch' in commit:
1972 1985 meta[b'branch'] = commit[b'branch']
1973 1986 node = commit.get(b'commit', commit.get(b'rev'))
1974 1987 if node:
1975 1988 meta[b'node'] = node
1976 1989 if len(commit.get(b'parents', ())) >= 1:
1977 1990 meta[b'parent'] = commit[b'parents'][0]
1978 1991 else:
1979 1992 meta = {}
1980 1993 if b'date' not in meta and b'dateCreated' in diff:
1981 1994 meta[b'date'] = b'%s 0' % diff[b'dateCreated']
1982 1995 if b'branch' not in meta and diff.get(b'branch'):
1983 1996 meta[b'branch'] = diff[b'branch']
1984 1997 if b'parent' not in meta and diff.get(b'sourceControlBaseRevision'):
1985 1998 meta[b'parent'] = diff[b'sourceControlBaseRevision']
1986 1999 return meta
1987 2000
1988 2001
1989 2002 def _getdrevs(ui, stack, specs):
1990 2003 """convert user supplied DREVSPECs into "Differential Revision" dicts
1991 2004
1992 2005 See ``hg help phabread`` for how to specify each DREVSPEC.
1993 2006 """
1994 2007 if len(specs) > 0:
1995 2008
1996 2009 def _formatspec(s):
1997 2010 if stack:
1998 2011 s = b':(%s)' % s
1999 2012 return b'(%s)' % s
2000 2013
2001 2014 spec = b'+'.join(pycompat.maplist(_formatspec, specs))
2002 2015
2003 2016 drevs = querydrev(ui, spec)
2004 2017 if drevs:
2005 2018 return drevs
2006 2019
2007 2020 raise error.Abort(_(b"empty DREVSPEC set"))
2008 2021
2009 2022
2010 2023 def readpatch(ui, drevs, write):
2011 2024 """generate plain-text patch readable by 'hg import'
2012 2025
2013 2026 write takes a list of (DREV, bytes), where DREV is the differential number
2014 2027 (as bytes, without the "D" prefix) and the bytes are the text of a patch
2015 2028 to be imported. drevs is what "querydrev" returns, results of
2016 2029 "differential.query".
2017 2030 """
2018 2031 # Prefetch hg:meta property for all diffs
2019 2032 diffids = sorted({max(int(v) for v in drev[b'diffs']) for drev in drevs})
2020 2033 diffs = callconduit(ui, b'differential.querydiffs', {b'ids': diffids})
2021 2034
2022 2035 patches = []
2023 2036
2024 2037 # Generate patch for each drev
2025 2038 for drev in drevs:
2026 2039 ui.note(_(b'reading D%s\n') % drev[b'id'])
2027 2040
2028 2041 diffid = max(int(v) for v in drev[b'diffs'])
2029 2042 body = callconduit(ui, b'differential.getrawdiff', {b'diffID': diffid})
2030 2043 desc = getdescfromdrev(drev)
2031 2044 header = b'# HG changeset patch\n'
2032 2045
2033 2046 # Try to preserve metadata from hg:meta property. Write hg patch
2034 2047 # headers that can be read by the "import" command. See patchheadermap
2035 2048 # and extract in mercurial/patch.py for supported headers.
2036 2049 meta = getdiffmeta(diffs[b'%d' % diffid])
2037 2050 for k in _metanamemap.keys():
2038 2051 if k in meta:
2039 2052 header += b'# %s %s\n' % (_metanamemap[k], meta[k])
2040 2053
2041 2054 content = b'%s%s\n%s' % (header, desc, body)
2042 2055 patches.append((drev[b'id'], content))
2043 2056
2044 2057 # Write patches to the supplied callback
2045 2058 write(patches)
2046 2059
2047 2060
2048 2061 @vcrcommand(
2049 2062 b'phabread',
2050 2063 [(b'', b'stack', False, _(b'read dependencies'))],
2051 2064 _(b'DREVSPEC... [OPTIONS]'),
2052 2065 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2053 2066 optionalrepo=True,
2054 2067 )
2055 2068 def phabread(ui, repo, *specs, **opts):
2056 2069 """print patches from Phabricator suitable for importing
2057 2070
2058 2071 DREVSPEC could be a Differential Revision identity, like ``D123``, or just
2059 2072 the number ``123``. It could also have common operators like ``+``, ``-``,
2060 2073 ``&``, ``(``, ``)`` for complex queries. Prefix ``:`` could be used to
2061 2074 select a stack. If multiple DREVSPEC values are given, the result is the
2062 2075 union of each individually evaluated value. No attempt is currently made
2063 2076 to reorder the values to run from parent to child.
2064 2077
2065 2078 ``abandoned``, ``accepted``, ``closed``, ``needsreview``, ``needsrevision``
2066 2079 could be used to filter patches by status. For performance reason, they
2067 2080 only represent a subset of non-status selections and cannot be used alone.
2068 2081
2069 2082 For example, ``:D6+8-(2+D4)`` selects a stack up to D6, plus D8 and exclude
2070 2083 D2 and D4. ``:D9 & needsreview`` selects "Needs Review" revisions in a
2071 2084 stack up to D9.
2072 2085
2073 2086 If --stack is given, follow dependencies information and read all patches.
2074 2087 It is equivalent to the ``:`` operator.
2075 2088 """
2076 2089 opts = pycompat.byteskwargs(opts)
2077 2090 drevs = _getdrevs(ui, opts.get(b'stack'), specs)
2078 2091
2079 2092 def _write(patches):
2080 2093 for drev, content in patches:
2081 2094 ui.write(content)
2082 2095
2083 2096 readpatch(ui, drevs, _write)
2084 2097
2085 2098
2086 2099 @vcrcommand(
2087 2100 b'phabimport',
2088 2101 [(b'', b'stack', False, _(b'import dependencies as well'))],
2089 2102 _(b'DREVSPEC... [OPTIONS]'),
2090 2103 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2091 2104 )
2092 2105 def phabimport(ui, repo, *specs, **opts):
2093 2106 """import patches from Phabricator for the specified Differential Revisions
2094 2107
2095 2108 The patches are read and applied starting at the parent of the working
2096 2109 directory.
2097 2110
2098 2111 See ``hg help phabread`` for how to specify DREVSPEC.
2099 2112 """
2100 2113 opts = pycompat.byteskwargs(opts)
2101 2114
2102 2115 # --bypass avoids losing exec and symlink bits when importing on Windows,
2103 2116 # and allows importing with a dirty wdir. It also aborts instead of leaving
2104 2117 # rejects.
2105 2118 opts[b'bypass'] = True
2106 2119
2107 2120 # Mandatory default values, synced with commands.import
2108 2121 opts[b'strip'] = 1
2109 2122 opts[b'prefix'] = b''
2110 2123 # Evolve 9.3.0 assumes this key is present in cmdutil.tryimportone()
2111 2124 opts[b'obsolete'] = False
2112 2125
2113 2126 if ui.configbool(b'phabimport', b'secret'):
2114 2127 opts[b'secret'] = True
2115 2128 if ui.configbool(b'phabimport', b'obsolete'):
2116 2129 opts[b'obsolete'] = True # Handled by evolve wrapping tryimportone()
2117 2130
2118 2131 def _write(patches):
2119 2132 parents = repo[None].parents()
2120 2133
2121 2134 with repo.wlock(), repo.lock(), repo.transaction(b'phabimport'):
2122 2135 for drev, contents in patches:
2123 2136 ui.status(_(b'applying patch from D%s\n') % drev)
2124 2137
2125 2138 with patch.extract(ui, pycompat.bytesio(contents)) as patchdata:
2126 2139 msg, node, rej = cmdutil.tryimportone(
2127 2140 ui,
2128 2141 repo,
2129 2142 patchdata,
2130 2143 parents,
2131 2144 opts,
2132 2145 [],
2133 2146 None, # Never update wdir to another revision
2134 2147 )
2135 2148
2136 2149 if not node:
2137 2150 raise error.Abort(_(b'D%s: no diffs found') % drev)
2138 2151
2139 2152 ui.note(msg + b'\n')
2140 2153 parents = [repo[node]]
2141 2154
2142 2155 drevs = _getdrevs(ui, opts.get(b'stack'), specs)
2143 2156
2144 2157 readpatch(repo.ui, drevs, _write)
2145 2158
2146 2159
2147 2160 @vcrcommand(
2148 2161 b'phabupdate',
2149 2162 [
2150 2163 (b'', b'accept', False, _(b'accept revisions')),
2151 2164 (b'', b'reject', False, _(b'reject revisions')),
2152 2165 (b'', b'abandon', False, _(b'abandon revisions')),
2153 2166 (b'', b'reclaim', False, _(b'reclaim revisions')),
2154 2167 (b'm', b'comment', b'', _(b'comment on the last revision')),
2155 2168 ],
2156 2169 _(b'DREVSPEC... [OPTIONS]'),
2157 2170 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2158 2171 optionalrepo=True,
2159 2172 )
2160 2173 def phabupdate(ui, repo, *specs, **opts):
2161 2174 """update Differential Revision in batch
2162 2175
2163 2176 DREVSPEC selects revisions. See :hg:`help phabread` for its usage.
2164 2177 """
2165 2178 opts = pycompat.byteskwargs(opts)
2166 2179 flags = [n for n in b'accept reject abandon reclaim'.split() if opts.get(n)]
2167 2180 if len(flags) > 1:
2168 2181 raise error.Abort(_(b'%s cannot be used together') % b', '.join(flags))
2169 2182
2170 2183 actions = []
2171 2184 for f in flags:
2172 2185 actions.append({b'type': f, b'value': True})
2173 2186
2174 2187 drevs = _getdrevs(ui, opts.get(b'stack'), specs)
2175 2188 for i, drev in enumerate(drevs):
2176 2189 if i + 1 == len(drevs) and opts.get(b'comment'):
2177 2190 actions.append({b'type': b'comment', b'value': opts[b'comment']})
2178 2191 if actions:
2179 2192 params = {
2180 2193 b'objectIdentifier': drev[b'phid'],
2181 2194 b'transactions': actions,
2182 2195 }
2183 2196 callconduit(ui, b'differential.revision.edit', params)
2184 2197
2185 2198
2186 2199 @eh.templatekeyword(b'phabreview', requires={b'ctx'})
2187 2200 def template_review(context, mapping):
2188 2201 """:phabreview: Object describing the review for this changeset.
2189 2202 Has attributes `url` and `id`.
2190 2203 """
2191 2204 ctx = context.resource(mapping, b'ctx')
2192 2205 m = _differentialrevisiondescre.search(ctx.description())
2193 2206 if m:
2194 2207 return templateutil.hybriddict(
2195 2208 {b'url': m.group('url'), b'id': b"D%s" % m.group('id'),}
2196 2209 )
2197 2210 else:
2198 2211 tags = ctx.repo().nodetags(ctx.node())
2199 2212 for t in tags:
2200 2213 if _differentialrevisiontagre.match(t):
2201 2214 url = ctx.repo().ui.config(b'phabricator', b'url')
2202 2215 if not url.endswith(b'/'):
2203 2216 url += b'/'
2204 2217 url += t
2205 2218
2206 2219 return templateutil.hybriddict({b'url': url, b'id': t,})
2207 2220 return None
2208 2221
2209 2222
2210 2223 @eh.templatekeyword(b'phabstatus', requires={b'ctx', b'repo', b'ui'})
2211 2224 def template_status(context, mapping):
2212 2225 """:phabstatus: String. Status of Phabricator differential.
2213 2226 """
2214 2227 ctx = context.resource(mapping, b'ctx')
2215 2228 repo = context.resource(mapping, b'repo')
2216 2229 ui = context.resource(mapping, b'ui')
2217 2230
2218 2231 rev = ctx.rev()
2219 2232 try:
2220 2233 drevid = getdrevmap(repo, [rev])[rev]
2221 2234 except KeyError:
2222 2235 return None
2223 2236 drevs = callconduit(ui, b'differential.query', {b'ids': [drevid]})
2224 2237 for drev in drevs:
2225 2238 if int(drev[b'id']) == drevid:
2226 2239 return templateutil.hybriddict(
2227 2240 {b'url': drev[b'uri'], b'status': drev[b'statusName'],}
2228 2241 )
2229 2242 return None
2230 2243
2231 2244
2232 2245 @show.showview(b'phabstatus', csettopic=b'work')
2233 2246 def phabstatusshowview(ui, repo, displayer):
2234 2247 """Phabricator differiential status"""
2235 2248 revs = repo.revs('sort(_underway(), topo)')
2236 2249 drevmap = getdrevmap(repo, revs)
2237 2250 unknownrevs, drevids, revsbydrevid = [], set(), {}
2238 2251 for rev, drevid in pycompat.iteritems(drevmap):
2239 2252 if drevid is not None:
2240 2253 drevids.add(drevid)
2241 2254 revsbydrevid.setdefault(drevid, set()).add(rev)
2242 2255 else:
2243 2256 unknownrevs.append(rev)
2244 2257
2245 2258 drevs = callconduit(ui, b'differential.query', {b'ids': list(drevids)})
2246 2259 drevsbyrev = {}
2247 2260 for drev in drevs:
2248 2261 for rev in revsbydrevid[int(drev[b'id'])]:
2249 2262 drevsbyrev[rev] = drev
2250 2263
2251 2264 def phabstatus(ctx):
2252 2265 drev = drevsbyrev[ctx.rev()]
2253 2266 status = ui.label(
2254 2267 b'%(statusName)s' % drev,
2255 2268 b'phabricator.status.%s' % _getstatusname(drev),
2256 2269 )
2257 2270 ui.write(b"\n%s %s\n" % (drev[b'uri'], status))
2258 2271
2259 2272 revs -= smartset.baseset(unknownrevs)
2260 2273 revdag = graphmod.dagwalker(repo, revs)
2261 2274
2262 2275 ui.setconfig(b'experimental', b'graphshorten', True)
2263 2276 displayer._exthook = phabstatus
2264 2277 nodelen = show.longestshortest(repo, revs)
2265 2278 logcmdutil.displaygraph(
2266 2279 ui,
2267 2280 repo,
2268 2281 revdag,
2269 2282 displayer,
2270 2283 graphmod.asciiedges,
2271 2284 props={b'nodelen': nodelen},
2272 2285 )
@@ -1,961 +1,965
1 1 #require vcr
2 2 $ cat >> $HGRCPATH <<EOF
3 3 > [extensions]
4 4 > phabricator =
5 5 >
6 6 > [auth]
7 7 > hgphab.schemes = https
8 8 > hgphab.prefix = phab.mercurial-scm.org
9 9 > # When working on the extension and making phabricator interaction
10 10 > # changes, edit this to be a real phabricator token. When done, edit
11 11 > # it back. The VCR transcripts will be auto-sanitised to replace your real
12 12 > # token with this value.
13 13 > hgphab.phabtoken = cli-hahayouwish
14 14 >
15 15 > [phabricator]
16 16 > debug = True
17 17 > EOF
18 18 $ hg init repo
19 19 $ cd repo
20 20 $ cat >> .hg/hgrc <<EOF
21 21 > [phabricator]
22 22 > url = https://phab.mercurial-scm.org/
23 23 > callsign = HG
24 24 > EOF
25 25 $ VCR="$TESTDIR/phabricator"
26 26
27 27 Error is handled reasonably. We override the phabtoken here so that
28 28 when you're developing changes to phabricator.py you can edit the
29 29 above config and have a real token in the test but not have to edit
30 30 this test.
31 31 $ hg phabread --config auth.hgphab.phabtoken=cli-notavalidtoken \
32 32 > --test-vcr "$VCR/phabread-conduit-error.json" D4480 | head
33 33 abort: Conduit Error (ERR-INVALID-AUTH): API token "cli-notavalidtoken" has the wrong length. API tokens should be 32 characters long.
34 34
35 35 Missing arguments don't crash, and may print the command help
36 36
37 37 $ hg debugcallconduit
38 38 hg debugcallconduit: invalid arguments
39 39 hg debugcallconduit METHOD
40 40
41 41 call Conduit API
42 42
43 43 options:
44 44
45 45 (use 'hg debugcallconduit -h' to show more help)
46 46 [255]
47 47 $ hg phabread
48 48 abort: empty DREVSPEC set
49 49 [255]
50 50
51 51 Basic phabread:
52 52 $ hg phabread --test-vcr "$VCR/phabread-4480.json" D4480 | head
53 53 # HG changeset patch
54 54 # Date 1536771503 0
55 55 # Parent a5de21c9e3703f8e8eb064bd7d893ff2f703c66a
56 56 exchangev2: start to implement pull with wire protocol v2
57 57
58 58 Wire protocol version 2 will take a substantially different
59 59 approach to exchange than version 1 (at least as far as pulling
60 60 is concerned).
61 61
62 62 This commit establishes a new exchangev2 module for holding
63 63
64 64 Phabread with multiple DREVSPEC
65 65
66 66 TODO: attempt to order related revisions like --stack?
67 67 $ hg phabread --test-vcr "$VCR/phabread-multi-drev.json" D8205 8206 D8207 \
68 68 > | grep '^Differential Revision'
69 69 Differential Revision: https://phab.mercurial-scm.org/D8205
70 70 Differential Revision: https://phab.mercurial-scm.org/D8206
71 71 Differential Revision: https://phab.mercurial-scm.org/D8207
72 72
73 73 Empty DREVSPECs don't crash
74 74
75 75 $ hg phabread --test-vcr "$VCR/phabread-empty-drev.json" D7917-D7917
76 76 abort: empty DREVSPEC set
77 77 [255]
78 78
79 79
80 80 phabupdate with an accept:
81 81 $ hg phabupdate --accept D4564 \
82 82 > -m 'I think I like where this is headed. Will read rest of series later.'\
83 83 > --test-vcr "$VCR/accept-4564.json"
84 84 abort: Conduit Error (ERR-CONDUIT-CORE): Validation errors:
85 85 - You can not accept this revision because it has already been closed. Only open revisions can be accepted.
86 86 [255]
87 87 $ hg phabupdate --accept D7913 -m 'LGTM' --test-vcr "$VCR/accept-7913.json"
88 88
89 89 Create a differential diff:
90 90 $ HGENCODING=utf-8; export HGENCODING
91 91 $ echo alpha > alpha
92 92 $ hg ci --addremove -m 'create alpha for phabricator test €'
93 93 adding alpha
94 94 $ hg phabsend -r . --test-vcr "$VCR/phabsend-create-alpha.json"
95 95 D7915 - created - d386117f30e6: create alpha for phabricator test \xe2\x82\xac (esc)
96 96 new commits: ['347bf67801e5']
97 97 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/d386117f30e6-24ffe649-phabsend.hg
98 98 $ echo more >> alpha
99 99 $ HGEDITOR=true hg ci --amend
100 100 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/347bf67801e5-3bf313e4-amend.hg
101 101 $ echo beta > beta
102 102 $ hg ci --addremove -m 'create beta for phabricator test'
103 103 adding beta
104 104 $ hg phabsend -r ".^::" --test-vcr "$VCR/phabsend-update-alpha-create-beta.json"
105 105 c44b38f24a45 mapped to old nodes []
106 106 D7915 - updated - c44b38f24a45: create alpha for phabricator test \xe2\x82\xac (esc)
107 107 D7916 - created - 9e6901f21d5b: create beta for phabricator test
108 108 new commits: ['a692622e6937']
109 109 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/9e6901f21d5b-1fcd4f0e-phabsend.hg
110 110 $ unset HGENCODING
111 111
112 112 The amend won't explode after posting a public commit. The local tag is left
113 113 behind to identify it.
114 114
115 115 $ echo 'public change' > beta
116 116 $ hg ci -m 'create public change for phabricator testing'
117 117 $ hg phase --public .
118 118 $ echo 'draft change' > alpha
119 119 $ hg ci -m 'create draft change for phabricator testing'
120 120 $ hg phabsend --amend -r '.^::' --test-vcr "$VCR/phabsend-create-public.json"
121 121 D7917 - created - 7b4185ab5d16: create public change for phabricator testing
122 122 D7918 - created - 251c1c333fc6: create draft change for phabricator testing
123 123 warning: not updating public commit 2:7b4185ab5d16
124 124 new commits: ['3244dc4a3334']
125 125 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/251c1c333fc6-41cb7c3b-phabsend.hg
126 126 $ hg tags -v
127 127 tip 3:3244dc4a3334
128 128 D7917 2:7b4185ab5d16 local
129 129
130 130 $ hg debugcallconduit user.search --test-vcr "$VCR/phab-conduit.json" <<EOF
131 131 > {
132 132 > "constraints": {
133 133 > "isBot": true
134 134 > }
135 135 > }
136 136 > EOF
137 137 {
138 138 "cursor": {
139 139 "after": null,
140 140 "before": null,
141 141 "limit": 100,
142 142 "order": null
143 143 },
144 144 "data": [],
145 145 "maps": {},
146 146 "query": {
147 147 "queryKey": null
148 148 }
149 149 }
150 150
151 151 Template keywords
152 152 $ hg log -T'{rev} {phabreview|json}\n'
153 153 3 {"id": "D7918", "url": "https://phab.mercurial-scm.org/D7918"}
154 154 2 {"id": "D7917", "url": "https://phab.mercurial-scm.org/D7917"}
155 155 1 {"id": "D7916", "url": "https://phab.mercurial-scm.org/D7916"}
156 156 0 {"id": "D7915", "url": "https://phab.mercurial-scm.org/D7915"}
157 157
158 158 $ hg log -T'{rev} {if(phabreview, "{phabreview.url} {phabreview.id}")}\n'
159 159 3 https://phab.mercurial-scm.org/D7918 D7918
160 160 2 https://phab.mercurial-scm.org/D7917 D7917
161 161 1 https://phab.mercurial-scm.org/D7916 D7916
162 162 0 https://phab.mercurial-scm.org/D7915 D7915
163 163
164 164 Commenting when phabsending:
165 165 $ echo comment > comment
166 166 $ hg ci --addremove -m "create comment for phabricator test"
167 167 adding comment
168 168 $ hg phabsend -r . -m "For default branch" --test-vcr "$VCR/phabsend-comment-created.json"
169 169 D7919 - created - d5dddca9023d: create comment for phabricator test
170 170 new commits: ['f7db812bbe1d']
171 171 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/d5dddca9023d-adf673ba-phabsend.hg
172 172 $ echo comment2 >> comment
173 173 $ hg ci --amend
174 174 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/f7db812bbe1d-8fcded77-amend.hg
175 175 $ hg phabsend -r . -m "Address review comments" --test-vcr "$VCR/phabsend-comment-updated.json"
176 176 1849d7828727 mapped to old nodes []
177 177 D7919 - updated - 1849d7828727: create comment for phabricator test
178 178
179 179 Phabsending a skipped commit:
180 180 $ hg phabsend --no-amend -r . --test-vcr "$VCR/phabsend-skipped.json"
181 181 1849d7828727 mapped to old nodes ['1849d7828727']
182 182 D7919 - skipped - 1849d7828727: create comment for phabricator test
183 183
184 Phabsend doesn't create an instability when rebasing existing revisions on top
184 Phabsend doesn't create an instability when restacking existing revisions on top
185 185 of new revisions.
186 186
187 187 $ hg init reorder
188 188 $ cd reorder
189 189 $ cat >> .hg/hgrc <<EOF
190 190 > [phabricator]
191 191 > url = https://phab.mercurial-scm.org/
192 192 > callsign = HG
193 193 > [experimental]
194 194 > evolution = all
195 195 > EOF
196 196
197 197 $ echo "add" > file1.txt
198 198 $ hg ci -Aqm 'added'
199 199 $ echo "mod1" > file1.txt
200 200 $ hg ci -m 'modified 1'
201 201 $ echo "mod2" > file1.txt
202 202 $ hg ci -m 'modified 2'
203 203 $ hg phabsend -r . --test-vcr "$VCR/phabsend-add-parent-setup.json"
204 204 D8433 - created - 5d3959e20d1d: modified 2
205 205 new commits: ['2b4aa8a88d61']
206 206 $ hg log -G -T compact
207 207 @ 3[tip]:1 2b4aa8a88d61 1970-01-01 00:00 +0000 test
208 208 | modified 2
209 209 |
210 210 o 1 d549263bcb2d 1970-01-01 00:00 +0000 test
211 211 | modified 1
212 212 |
213 213 o 0 5cbade24e0fa 1970-01-01 00:00 +0000 test
214 214 added
215 215
216 216 Also check that it doesn't create more orphans outside of the stack
217 217
218 218 $ hg up -q 1
219 219 $ echo "mod3" > file1.txt
220 220 $ hg ci -m 'modified 3'
221 221 created new head
222 222 $ hg up -q 3
223 223 $ hg phabsend -r ".^ + ." --test-vcr "$VCR/phabsend-add-parent.json"
224 224 2b4aa8a88d61 mapped to old nodes ['2b4aa8a88d61']
225 225 D8434 - created - d549263bcb2d: modified 1
226 226 D8433 - updated - 2b4aa8a88d61: modified 2
227 227 new commits: ['876a60d024de']
228 228 new commits: ['0c6523cb1d0f']
229 229 restabilizing 1eda4bf55021 as d2c78c3a3e01
230 230 $ hg log -G -T compact
231 231 o 7[tip]:5 d2c78c3a3e01 1970-01-01 00:00 +0000 test
232 232 | modified 3
233 233 |
234 234 | @ 6 0c6523cb1d0f 1970-01-01 00:00 +0000 test
235 235 |/ modified 2
236 236 |
237 237 o 5:0 876a60d024de 1970-01-01 00:00 +0000 test
238 238 | modified 1
239 239 |
240 240 o 0 5cbade24e0fa 1970-01-01 00:00 +0000 test
241 241 added
242 242
243 243 Posting obsolete commits is disallowed
244 244
245 245 $ echo "mod3" > file1.txt
246 246 $ hg ci -m 'modified A'
247 247 $ echo "mod4" > file1.txt
248 248 $ hg ci -m 'modified B'
249 249
250 250 $ hg up '.^'
251 251 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
252 252 $ echo 'obsolete' > file1.txt
253 253 $ hg amend --config extensions.amend=
254 254 1 new orphan changesets
255 255 $ hg log -G
256 256 @ changeset: 10:082be6c94150
257 257 | tag: tip
258 258 | parent: 6:0c6523cb1d0f
259 259 | user: test
260 260 | date: Thu Jan 01 00:00:00 1970 +0000
261 261 | summary: modified A
262 262 |
263 263 | * changeset: 9:a67643f48146
264 264 | | user: test
265 265 | | date: Thu Jan 01 00:00:00 1970 +0000
266 266 | | instability: orphan
267 267 | | summary: modified B
268 268 | |
269 269 | x changeset: 8:db79727cb2f7
270 270 |/ parent: 6:0c6523cb1d0f
271 271 | user: test
272 272 | date: Thu Jan 01 00:00:00 1970 +0000
273 273 | obsolete: rewritten using amend as 10:082be6c94150
274 274 | summary: modified A
275 275 |
276 276 | o changeset: 7:d2c78c3a3e01
277 277 | | parent: 5:876a60d024de
278 278 | | user: test
279 279 | | date: Thu Jan 01 00:00:00 1970 +0000
280 280 | | summary: modified 3
281 281 | |
282 282 o | changeset: 6:0c6523cb1d0f
283 283 |/ user: test
284 284 | date: Thu Jan 01 00:00:00 1970 +0000
285 285 | summary: modified 2
286 286 |
287 287 o changeset: 5:876a60d024de
288 288 | parent: 0:5cbade24e0fa
289 289 | user: test
290 290 | date: Thu Jan 01 00:00:00 1970 +0000
291 291 | summary: modified 1
292 292 |
293 293 o changeset: 0:5cbade24e0fa
294 294 user: test
295 295 date: Thu Jan 01 00:00:00 1970 +0000
296 296 summary: added
297 297
298 298 $ hg phabsend -r 5::
299 299 abort: obsolete commits cannot be posted for review
300 300 [255]
301 301
302 302 Don't restack existing orphans
303 303
304 304 $ hg phabsend -r 5::tip --test-vcr "$VCR/phabsend-no-restack-orphan.json"
305 305 876a60d024de mapped to old nodes ['876a60d024de']
306 306 0c6523cb1d0f mapped to old nodes ['0c6523cb1d0f']
307 307 D8434 - updated - 876a60d024de: modified 1
308 308 D8433 - updated - 0c6523cb1d0f: modified 2
309 309 D8435 - created - 082be6c94150: modified A
310 310 new commits: ['b5913193c805']
311 311 not restabilizing unchanged d2c78c3a3e01
312 312 $ hg log -G
313 313 @ changeset: 11:b5913193c805
314 314 | tag: tip
315 315 | parent: 6:0c6523cb1d0f
316 316 | user: test
317 317 | date: Thu Jan 01 00:00:00 1970 +0000
318 318 | summary: modified A
319 319 |
320 320 | * changeset: 9:a67643f48146
321 321 | | user: test
322 322 | | date: Thu Jan 01 00:00:00 1970 +0000
323 323 | | instability: orphan
324 324 | | summary: modified B
325 325 | |
326 326 | x changeset: 8:db79727cb2f7
327 327 |/ parent: 6:0c6523cb1d0f
328 328 | user: test
329 329 | date: Thu Jan 01 00:00:00 1970 +0000
330 330 | obsolete: rewritten using amend, phabsend as 11:b5913193c805
331 331 | summary: modified A
332 332 |
333 333 | o changeset: 7:d2c78c3a3e01
334 334 | | parent: 5:876a60d024de
335 335 | | user: test
336 336 | | date: Thu Jan 01 00:00:00 1970 +0000
337 337 | | summary: modified 3
338 338 | |
339 339 o | changeset: 6:0c6523cb1d0f
340 340 |/ user: test
341 341 | date: Thu Jan 01 00:00:00 1970 +0000
342 342 | summary: modified 2
343 343 |
344 344 o changeset: 5:876a60d024de
345 345 | parent: 0:5cbade24e0fa
346 346 | user: test
347 347 | date: Thu Jan 01 00:00:00 1970 +0000
348 348 | summary: modified 1
349 349 |
350 350 o changeset: 0:5cbade24e0fa
351 351 user: test
352 352 date: Thu Jan 01 00:00:00 1970 +0000
353 353 summary: added
354 354
355 355 $ cd ..
356 356
357 357 Phabesending a new binary, a modified binary, and a removed binary
358 358
359 359 >>> open('bin', 'wb').write(b'\0a') and None
360 360 $ hg ci -Am 'add binary'
361 361 adding bin
362 362 >>> open('bin', 'wb').write(b'\0b') and None
363 363 $ hg ci -m 'modify binary'
364 364 $ hg rm bin
365 365 $ hg ci -m 'remove binary'
366 366 $ hg phabsend -r .~2:: --test-vcr "$VCR/phabsend-binary.json"
367 367 uploading bin@aa24a81f55de
368 368 D8007 - created - aa24a81f55de: add binary
369 369 uploading bin@d8d62a881b54
370 370 D8008 - created - d8d62a881b54: modify binary
371 371 D8009 - created - af55645b2e29: remove binary
372 372 new commits: ['b8139fbb4a57']
373 373 new commits: ['c88ce4c2d2ad']
374 374 new commits: ['75dbbc901145']
375 375 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/aa24a81f55de-a3a0cf24-phabsend.hg
376 376
377 377 Phabsend a renamed binary and a copied binary, with and without content changes
378 378 to src and dest
379 379
380 380 >>> open('bin2', 'wb').write(b'\0c') and None
381 381 $ hg ci -Am 'add another binary'
382 382 adding bin2
383 383
384 384 TODO: "bin2" can't be viewed in this commit (left or right side), and the URL
385 385 looks much different than when viewing "bin2_moved". No idea if this is a phab
386 386 bug, or phabsend bug. The patch (as printed by phabread) look reasonable
387 387 though.
388 388
389 389 $ hg mv bin2 bin2_moved
390 390 $ hg ci -m "moved binary"
391 391
392 392 Note: "bin2_moved" is also not viewable in phabricator with this review
393 393
394 394 $ hg cp bin2_moved bin2_copied
395 395 $ hg ci -m "copied binary"
396 396
397 397 Note: "bin2_moved_again" is marked binary in phabricator, and both sides of it
398 398 are viewable in their proper state. "bin2_copied" is not viewable, and not
399 399 listed as binary in phabricator.
400 400
401 401 >>> open('bin2_copied', 'wb').write(b'\0move+mod') and None
402 402 $ hg mv bin2_copied bin2_moved_again
403 403 $ hg ci -m "move+mod copied binary"
404 404
405 405 Note: "bin2_moved" and "bin2_moved_copy" are both marked binary, and both
406 406 viewable on each side.
407 407
408 408 >>> open('bin2_moved', 'wb').write(b'\0precopy mod') and None
409 409 $ hg cp bin2_moved bin2_moved_copied
410 410 >>> open('bin2_moved', 'wb').write(b'\0copy src+mod') and None
411 411 $ hg ci -m "copy+mod moved binary"
412 412
413 413 $ hg phabsend -r .~4:: --test-vcr "$VCR/phabsend-binary-renames.json"
414 414 uploading bin2@f42f9195e00c
415 415 D8128 - created - f42f9195e00c: add another binary
416 416 D8129 - created - 834ab31d80ae: moved binary
417 417 D8130 - created - 494b750e5194: copied binary
418 418 uploading bin2_moved_again@25f766b50cc2
419 419 D8131 - created - 25f766b50cc2: move+mod copied binary
420 420 uploading bin2_moved_copied@1b87b363a5e4
421 421 uploading bin2_moved@1b87b363a5e4
422 422 D8132 - created - 1b87b363a5e4: copy+mod moved binary
423 423 new commits: ['90437c20312a']
424 424 new commits: ['f391f4da4c61']
425 425 new commits: ['da86a9f3268c']
426 426 new commits: ['003ffc16ba66']
427 427 new commits: ['13bd750c36fa']
428 428 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/f42f9195e00c-e82a0769-phabsend.hg
429 429
430 430 Phabreading a DREV with a local:commits time as a string:
431 431 $ hg phabread --test-vcr "$VCR/phabread-str-time.json" D1285
432 432 # HG changeset patch
433 433 # User Pulkit Goyal <7895pulkit@gmail.com>
434 434 # Date 1509404054 -19800
435 435 # Node ID 44fc1c1f1774a76423b9c732af6938435099bcc5
436 436 # Parent 8feef8ef8389a3b544e0a74624f1efc3a8d85d35
437 437 repoview: add a new attribute _visibilityexceptions and related API
438 438
439 439 Currently we don't have a defined way in core to make some hidden revisions
440 440 visible in filtered repo. Extensions to achieve the purpose of unhiding some
441 441 hidden commits, wrap repoview.pinnedrevs() function.
442 442
443 443 To make the above task simple and have well defined API, this patch adds a new
444 444 attribute '_visibilityexceptions' to repoview class which will contains
445 445 the hidden revs which should be exception.
446 446 This will allow to set different exceptions for different repoview objects
447 447 backed by the same unfiltered repo.
448 448
449 449 This patch also adds API to add revs to the attribute set and get them.
450 450
451 451 Thanks to Jun for suggesting the use of repoview class instead of localrepo.
452 452
453 453 Differential Revision: https://phab.mercurial-scm.org/D1285
454 454 diff --git a/mercurial/repoview.py b/mercurial/repoview.py
455 455 --- a/mercurial/repoview.py
456 456 +++ b/mercurial/repoview.py
457 457 @@ * @@ (glob)
458 458 subclasses of `localrepo`. Eg: `bundlerepo` or `statichttprepo`.
459 459 """
460 460
461 461 + # hidden revs which should be visible
462 462 + _visibilityexceptions = set()
463 463 +
464 464 def __init__(self, repo, filtername):
465 465 object.__setattr__(self, r'_unfilteredrepo', repo)
466 466 object.__setattr__(self, r'filtername', filtername)
467 467 @@ -231,6 +234,14 @@
468 468 return self
469 469 return self.unfiltered().filtered(name)
470 470
471 471 + def addvisibilityexceptions(self, revs):
472 472 + """adds hidden revs which should be visible to set of exceptions"""
473 473 + self._visibilityexceptions.update(revs)
474 474 +
475 475 + def getvisibilityexceptions(self):
476 476 + """returns the set of hidden revs which should be visible"""
477 477 + return self._visibilityexceptions
478 478 +
479 479 # everything access are forwarded to the proxied repo
480 480 def __getattr__(self, attr):
481 481 return getattr(self._unfilteredrepo, attr)
482 482 diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
483 483 --- a/mercurial/localrepo.py
484 484 +++ b/mercurial/localrepo.py
485 485 @@ -570,6 +570,14 @@
486 486 def close(self):
487 487 self._writecaches()
488 488
489 489 + def addvisibilityexceptions(self, exceptions):
490 490 + # should be called on a filtered repository
491 491 + pass
492 492 +
493 493 + def getvisibilityexceptions(self):
494 494 + # should be called on a filtered repository
495 495 + return set()
496 496 +
497 497 def _loadextensions(self):
498 498 extensions.loadall(self.ui)
499 499
500 500
501 501 A bad .arcconfig doesn't error out
502 502 $ echo 'garbage' > .arcconfig
503 503 $ hg config phabricator --debug
504 504 invalid JSON in $TESTTMP/repo/.arcconfig
505 505 read config from: */.hgrc (glob)
506 506 */.hgrc:*: phabricator.debug=True (glob)
507 507 $TESTTMP/repo/.hg/hgrc:*: phabricator.url=https://phab.mercurial-scm.org/ (glob)
508 508 $TESTTMP/repo/.hg/hgrc:*: phabricator.callsign=HG (glob)
509 509
510 510 The .arcconfig content overrides global config
511 511 $ cat >> $HGRCPATH << EOF
512 512 > [phabricator]
513 513 > url = global
514 514 > callsign = global
515 515 > EOF
516 516 $ cp $TESTDIR/../.arcconfig .
517 517 $ mv .hg/hgrc .hg/hgrc.bak
518 518 $ hg config phabricator --debug
519 519 read config from: */.hgrc (glob)
520 520 */.hgrc:*: phabricator.debug=True (glob)
521 521 $TESTTMP/repo/.arcconfig: phabricator.callsign=HG
522 522 $TESTTMP/repo/.arcconfig: phabricator.url=https://phab.mercurial-scm.org/
523 523
524 524 But it doesn't override local config
525 525 $ cat >> .hg/hgrc << EOF
526 526 > [phabricator]
527 527 > url = local
528 528 > callsign = local
529 529 > EOF
530 530 $ hg config phabricator --debug
531 531 read config from: */.hgrc (glob)
532 532 */.hgrc:*: phabricator.debug=True (glob)
533 533 $TESTTMP/repo/.hg/hgrc:*: phabricator.url=local (glob)
534 534 $TESTTMP/repo/.hg/hgrc:*: phabricator.callsign=local (glob)
535 535 $ mv .hg/hgrc.bak .hg/hgrc
536 536
537 537 Phabimport works with a stack
538 538
539 539 $ cd ..
540 540 $ hg clone repo repo2 -qr 1
541 541 $ cp repo/.hg/hgrc repo2/.hg/
542 542 $ cd repo2
543 543 $ hg phabimport --stack 'D7918' --test-vcr "$VCR/phabimport-stack.json"
544 544 applying patch from D7917
545 545 applying patch from D7918
546 546 $ hg log -r .: -G -Tcompact
547 547 o 3[tip] aaef04066140 1970-01-01 00:00 +0000 test
548 548 | create draft change for phabricator testing
549 549 |
550 550 o 2 8de3712202d1 1970-01-01 00:00 +0000 test
551 551 | create public change for phabricator testing
552 552 |
553 553 @ 1 a692622e6937 1970-01-01 00:00 +0000 test
554 554 | create beta for phabricator test
555 555 ~
556 556 Phabimport can create secret commits
557 557
558 558 $ hg rollback --config ui.rollback=True
559 559 repository tip rolled back to revision 1 (undo phabimport)
560 560 $ hg phabimport --stack 'D7918' --test-vcr "$VCR/phabimport-stack.json" \
561 561 > --config phabimport.secret=True
562 562 applying patch from D7917
563 563 applying patch from D7918
564 564 $ hg log -r 'reverse(.:)' -T phases
565 565 changeset: 3:aaef04066140
566 566 tag: tip
567 567 phase: secret
568 568 user: test
569 569 date: Thu Jan 01 00:00:00 1970 +0000
570 570 summary: create draft change for phabricator testing
571 571
572 572 changeset: 2:8de3712202d1
573 573 phase: secret
574 574 user: test
575 575 date: Thu Jan 01 00:00:00 1970 +0000
576 576 summary: create public change for phabricator testing
577 577
578 578 changeset: 1:a692622e6937
579 579 phase: public
580 580 user: test
581 581 date: Thu Jan 01 00:00:00 1970 +0000
582 582 summary: create beta for phabricator test
583 583
584 584 Phabimport accepts multiple DREVSPECs
585 585
586 586 $ hg rollback --config ui.rollback=True
587 587 repository tip rolled back to revision 1 (undo phabimport)
588 588 $ hg phabimport --no-stack D7917 D7918 --test-vcr "$VCR/phabimport-multi-drev.json"
589 589 applying patch from D7917
590 590 applying patch from D7918
591 591
592 Phabsend requires a linear range of commits
593
594 $ hg phabsend -r 0+2+3
595 abort: cannot phabsend multiple head revisions: c44b38f24a45
596 (the revisions must form a linear chain)
597 [255]
598
592 599 Validate arguments with --fold
593 600
594 601 $ hg phabsend --fold -r 1
595 602 abort: cannot fold a single revision
596 603 [255]
597 604 $ hg phabsend --fold --no-amend -r 1::
598 605 abort: cannot fold with --no-amend
599 606 [255]
600 $ hg phabsend --fold -r 0+3
601 abort: cannot fold non-linear revisions
602 [255]
603 607 $ hg phabsend --fold -r 1::
604 608 abort: cannot fold revisions with different DREV values
605 609 [255]
606 610
607 611 Setup a series of commits to be folded, and include the Test Plan field multiple
608 612 times to test the concatenation logic. No Test Plan field in the last one to
609 613 ensure missing fields are skipped.
610 614
611 615 $ hg init ../folded
612 616 $ cd ../folded
613 617 $ cat >> .hg/hgrc <<EOF
614 618 > [phabricator]
615 619 > url = https://phab.mercurial-scm.org/
616 620 > callsign = HG
617 621 > EOF
618 622
619 623 $ echo 'added' > file.txt
620 624 $ hg ci -Aqm 'added file'
621 625
622 626 $ cat > log.txt <<EOF
623 627 > one: first commit to review
624 628 >
625 629 > This file was modified with 'mod1' as its contents.
626 630 >
627 631 > Test Plan:
628 632 > LOL! What testing?!
629 633 > EOF
630 634 $ echo mod1 > file.txt
631 635 $ hg ci -l log.txt
632 636
633 637 $ cat > log.txt <<EOF
634 638 > two: second commit to review
635 639 >
636 640 > This file was modified with 'mod2' as its contents.
637 641 >
638 642 > Test Plan:
639 643 > Haha! yeah, right.
640 644 >
641 645 > EOF
642 646 $ echo mod2 > file.txt
643 647 $ hg ci -l log.txt
644 648
645 649 $ echo mod3 > file.txt
646 650 $ hg ci -m '3: a commit with no detailed message'
647 651
648 652 The folding of immutable commits works...
649 653
650 654 $ hg phase -r tip --public
651 655 $ hg phabsend --fold -r 1:: --test-vcr "$VCR/phabsend-fold-immutable.json"
652 656 D8386 - created - a959a3f69d8d: one: first commit to review
653 657 D8386 - created - 24a4438154ba: two: second commit to review
654 658 D8386 - created - d235829e802c: 3: a commit with no detailed message
655 659 warning: not updating public commit 1:a959a3f69d8d
656 660 warning: not updating public commit 2:24a4438154ba
657 661 warning: not updating public commit 3:d235829e802c
658 662 no newnodes to update
659 663
660 664 $ hg phase -r 0 --draft --force
661 665
662 666 ... as does the initial mutable fold...
663 667
664 668 $ echo y | hg phabsend --fold --confirm -r 1:: \
665 669 > --test-vcr "$VCR/phabsend-fold-initial.json"
666 670 NEW - a959a3f69d8d: one: first commit to review
667 671 NEW - 24a4438154ba: two: second commit to review
668 672 NEW - d235829e802c: 3: a commit with no detailed message
669 673 Send the above changes to https://phab.mercurial-scm.org/ (yn)? y
670 674 D8387 - created - a959a3f69d8d: one: first commit to review
671 675 D8387 - created - 24a4438154ba: two: second commit to review
672 676 D8387 - created - d235829e802c: 3: a commit with no detailed message
673 677 updating local commit list for D8387
674 678 new commits: ['602c4e738243', '832553266fe8', '921f8265efbd']
675 679 saved backup bundle to $TESTTMP/folded/.hg/strip-backup/a959a3f69d8d-a4a24136-phabsend.hg
676 680
677 681 ... and doesn't mangle the local commits.
678 682
679 683 $ hg log -T '{rev}:{node|short}\n{indent(desc, " ")}\n'
680 684 3:921f8265efbd
681 685 3: a commit with no detailed message
682 686
683 687 Differential Revision: https://phab.mercurial-scm.org/D8387
684 688 2:832553266fe8
685 689 two: second commit to review
686 690
687 691 This file was modified with 'mod2' as its contents.
688 692
689 693 Test Plan:
690 694 Haha! yeah, right.
691 695
692 696 Differential Revision: https://phab.mercurial-scm.org/D8387
693 697 1:602c4e738243
694 698 one: first commit to review
695 699
696 700 This file was modified with 'mod1' as its contents.
697 701
698 702 Test Plan:
699 703 LOL! What testing?!
700 704
701 705 Differential Revision: https://phab.mercurial-scm.org/D8387
702 706 0:98d480e0d494
703 707 added file
704 708
705 709 Setup some obsmarkers by adding a file to the middle commit. This stress tests
706 710 getoldnodedrevmap() in later phabsends.
707 711
708 712 $ hg up '.^'
709 713 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
710 714 $ echo 'modified' > file2.txt
711 715 $ hg add file2.txt
712 716 $ hg amend --config experimental.evolution=all --config extensions.amend=
713 717 1 new orphan changesets
714 718 $ hg up 3
715 719 obsolete feature not enabled but 1 markers found!
716 720 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
717 721 $ hg rebase --config experimental.evolution=all --config extensions.rebase=
718 722 note: not rebasing 2:832553266fe8 "two: second commit to review", already in destination as 4:0124e5474c88 "two: second commit to review" (tip)
719 723 rebasing 3:921f8265efbd "3: a commit with no detailed message"
720 724
721 725 When commits have changed locally, the local commit list on Phabricator is
722 726 updated.
723 727
724 728 $ echo y | hg phabsend --fold --confirm -r 1:: \
725 729 > --test-vcr "$VCR/phabsend-fold-updated.json"
726 730 obsolete feature not enabled but 2 markers found!
727 731 602c4e738243 mapped to old nodes ['602c4e738243']
728 732 0124e5474c88 mapped to old nodes ['832553266fe8']
729 733 e4edb1fe3565 mapped to old nodes ['921f8265efbd']
730 734 D8387 - 602c4e738243: one: first commit to review
731 735 D8387 - 0124e5474c88: two: second commit to review
732 736 D8387 - e4edb1fe3565: 3: a commit with no detailed message
733 737 Send the above changes to https://phab.mercurial-scm.org/ (yn)? y
734 738 D8387 - updated - 602c4e738243: one: first commit to review
735 739 D8387 - updated - 0124e5474c88: two: second commit to review
736 740 D8387 - updated - e4edb1fe3565: 3: a commit with no detailed message
737 741 obsolete feature not enabled but 2 markers found! (?)
738 742 updating local commit list for D8387
739 743 new commits: ['602c4e738243', '0124e5474c88', 'e4edb1fe3565']
740 744 $ hg log -Tcompact
741 745 obsolete feature not enabled but 2 markers found!
742 746 5[tip] e4edb1fe3565 1970-01-01 00:00 +0000 test
743 747 3: a commit with no detailed message
744 748
745 749 4:1 0124e5474c88 1970-01-01 00:00 +0000 test
746 750 two: second commit to review
747 751
748 752 1 602c4e738243 1970-01-01 00:00 +0000 test
749 753 one: first commit to review
750 754
751 755 0 98d480e0d494 1970-01-01 00:00 +0000 test
752 756 added file
753 757
754 758 When nothing has changed locally since the last phabsend, the commit list isn't
755 759 updated, and nothing is changed locally afterward.
756 760
757 761 $ hg phabsend --fold -r 1:: --test-vcr "$VCR/phabsend-fold-no-changes.json"
758 762 obsolete feature not enabled but 2 markers found!
759 763 602c4e738243 mapped to old nodes ['602c4e738243']
760 764 0124e5474c88 mapped to old nodes ['0124e5474c88']
761 765 e4edb1fe3565 mapped to old nodes ['e4edb1fe3565']
762 766 D8387 - updated - 602c4e738243: one: first commit to review
763 767 D8387 - updated - 0124e5474c88: two: second commit to review
764 768 D8387 - updated - e4edb1fe3565: 3: a commit with no detailed message
765 769 obsolete feature not enabled but 2 markers found! (?)
766 770 local commit list for D8387 is already up-to-date
767 771 $ hg log -Tcompact
768 772 obsolete feature not enabled but 2 markers found!
769 773 5[tip] e4edb1fe3565 1970-01-01 00:00 +0000 test
770 774 3: a commit with no detailed message
771 775
772 776 4:1 0124e5474c88 1970-01-01 00:00 +0000 test
773 777 two: second commit to review
774 778
775 779 1 602c4e738243 1970-01-01 00:00 +0000 test
776 780 one: first commit to review
777 781
778 782 0 98d480e0d494 1970-01-01 00:00 +0000 test
779 783 added file
780 784
781 785 Fold will accept new revisions at the end...
782 786
783 787 $ echo 'another mod' > file2.txt
784 788 $ hg ci -m 'four: extend the fold range'
785 789 obsolete feature not enabled but 2 markers found!
786 790 $ hg phabsend --fold -r 1:: --test-vcr "$VCR/phabsend-fold-extend-end.json" \
787 791 > --config experimental.evolution=all
788 792 602c4e738243 mapped to old nodes ['602c4e738243']
789 793 0124e5474c88 mapped to old nodes ['0124e5474c88']
790 794 e4edb1fe3565 mapped to old nodes ['e4edb1fe3565']
791 795 D8387 - updated - 602c4e738243: one: first commit to review
792 796 D8387 - updated - 0124e5474c88: two: second commit to review
793 797 D8387 - updated - e4edb1fe3565: 3: a commit with no detailed message
794 798 D8387 - created - 94aaae213b23: four: extend the fold range
795 799 updating local commit list for D8387
796 800 new commits: ['602c4e738243', '0124e5474c88', 'e4edb1fe3565', '51a04fea8707']
797 801 $ hg log -r . -T '{desc}\n'
798 802 four: extend the fold range
799 803
800 804 Differential Revision: https://phab.mercurial-scm.org/D8387
801 805 $ hg log -T'{rev} {if(phabreview, "{phabreview.url} {phabreview.id}")}\n' -r 1::
802 806 obsolete feature not enabled but 3 markers found!
803 807 1 https://phab.mercurial-scm.org/D8387 D8387
804 808 4 https://phab.mercurial-scm.org/D8387 D8387
805 809 5 https://phab.mercurial-scm.org/D8387 D8387
806 810 7 https://phab.mercurial-scm.org/D8387 D8387
807 811
808 812 ... and also accepts new revisions at the beginning of the range
809 813
810 814 It's a bit unfortunate that not having a Differential URL on the first commit
811 815 causes a new Differential Revision to be created, though it isn't *entirely*
812 816 unreasonable. At least this updates the subsequent commits.
813 817
814 818 TODO: See if it can reuse the existing Differential.
815 819
816 820 $ hg phabsend --fold -r 0:: --test-vcr "$VCR/phabsend-fold-extend-front.json" \
817 821 > --config experimental.evolution=all
818 822 602c4e738243 mapped to old nodes ['602c4e738243']
819 823 0124e5474c88 mapped to old nodes ['0124e5474c88']
820 824 e4edb1fe3565 mapped to old nodes ['e4edb1fe3565']
821 825 51a04fea8707 mapped to old nodes ['51a04fea8707']
822 826 D8388 - created - 98d480e0d494: added file
823 827 D8388 - updated - 602c4e738243: one: first commit to review
824 828 D8388 - updated - 0124e5474c88: two: second commit to review
825 829 D8388 - updated - e4edb1fe3565: 3: a commit with no detailed message
826 830 D8388 - updated - 51a04fea8707: four: extend the fold range
827 831 updating local commit list for D8388
828 832 new commits: ['15e9b14b4b4c', '6320b7d714cf', '3ee132d41dbc', '30682b960804', 'ac7db67f0991']
829 833
830 834 $ hg log -T '{rev}:{node|short}\n{indent(desc, " ")}\n'
831 835 obsolete feature not enabled but 8 markers found!
832 836 12:ac7db67f0991
833 837 four: extend the fold range
834 838
835 839 Differential Revision: https://phab.mercurial-scm.org/D8388
836 840 11:30682b960804
837 841 3: a commit with no detailed message
838 842
839 843 Differential Revision: https://phab.mercurial-scm.org/D8388
840 844 10:3ee132d41dbc
841 845 two: second commit to review
842 846
843 847 This file was modified with 'mod2' as its contents.
844 848
845 849 Test Plan:
846 850 Haha! yeah, right.
847 851
848 852 Differential Revision: https://phab.mercurial-scm.org/D8388
849 853 9:6320b7d714cf
850 854 one: first commit to review
851 855
852 856 This file was modified with 'mod1' as its contents.
853 857
854 858 Test Plan:
855 859 LOL! What testing?!
856 860
857 861 Differential Revision: https://phab.mercurial-scm.org/D8388
858 862 8:15e9b14b4b4c
859 863 added file
860 864
861 865 Differential Revision: https://phab.mercurial-scm.org/D8388
862 866
863 867 Test phabsend --fold with an `hg split` at the end of the range
864 868
865 869 $ echo foo > file3.txt
866 870 $ hg add file3.txt
867 871
868 872 $ hg log -r . -T '{desc}' > log.txt
869 873 $ echo 'amended mod' > file2.txt
870 874 $ hg ci --amend -l log.txt --config experimental.evolution=all
871 875
872 876 $ cat <<EOF | hg --config extensions.split= --config ui.interactive=True \
873 877 > --config experimental.evolution=all split -r .
874 878 > n
875 879 > y
876 880 > y
877 881 > y
878 882 > y
879 883 > EOF
880 884 diff --git a/file2.txt b/file2.txt
881 885 1 hunks, 1 lines changed
882 886 examine changes to 'file2.txt'?
883 887 (enter ? for help) [Ynesfdaq?] n
884 888
885 889 diff --git a/file3.txt b/file3.txt
886 890 new file mode 100644
887 891 examine changes to 'file3.txt'?
888 892 (enter ? for help) [Ynesfdaq?] y
889 893
890 894 @@ -0,0 +1,1 @@
891 895 +foo
892 896 record change 2/2 to 'file3.txt'?
893 897 (enter ? for help) [Ynesfdaq?] y
894 898
895 899 created new head
896 900 diff --git a/file2.txt b/file2.txt
897 901 1 hunks, 1 lines changed
898 902 examine changes to 'file2.txt'?
899 903 (enter ? for help) [Ynesfdaq?] y
900 904
901 905 @@ -1,1 +1,1 @@
902 906 -modified
903 907 +amended mod
904 908 record this change to 'file2.txt'?
905 909 (enter ? for help) [Ynesfdaq?] y
906 910
907 911 $ hg phabsend --fold -r 8:: --test-vcr "$VCR/phabsend-fold-split-end.json" \
908 912 > --config experimental.evolution=all
909 913 15e9b14b4b4c mapped to old nodes ['15e9b14b4b4c']
910 914 6320b7d714cf mapped to old nodes ['6320b7d714cf']
911 915 3ee132d41dbc mapped to old nodes ['3ee132d41dbc']
912 916 30682b960804 mapped to old nodes ['30682b960804']
913 917 6bc15dc99efd mapped to old nodes ['ac7db67f0991']
914 918 b50946d5e490 mapped to old nodes ['ac7db67f0991']
915 919 D8388 - updated - 15e9b14b4b4c: added file
916 920 D8388 - updated - 6320b7d714cf: one: first commit to review
917 921 D8388 - updated - 3ee132d41dbc: two: second commit to review
918 922 D8388 - updated - 30682b960804: 3: a commit with no detailed message
919 923 D8388 - updated - 6bc15dc99efd: four: extend the fold range
920 924 D8388 - updated - b50946d5e490: four: extend the fold range
921 925 updating local commit list for D8388
922 926 new commits: ['15e9b14b4b4c', '6320b7d714cf', '3ee132d41dbc', '30682b960804', '6bc15dc99efd', 'b50946d5e490']
923 927
924 928 Test phabsend --fold with an `hg fold` at the end of the range
925 929
926 930 $ hg --config experimental.evolution=all --config extensions.rebase= \
927 931 > rebase -r '.^' -r . -d '.^^' --collapse -l log.txt
928 932 rebasing 14:6bc15dc99efd "four: extend the fold range"
929 933 rebasing 15:b50946d5e490 "four: extend the fold range" (tip)
930 934
931 935 $ hg phabsend --fold -r 8:: --test-vcr "$VCR/phabsend-fold-fold-end.json" \
932 936 > --config experimental.evolution=all
933 937 15e9b14b4b4c mapped to old nodes ['15e9b14b4b4c']
934 938 6320b7d714cf mapped to old nodes ['6320b7d714cf']
935 939 3ee132d41dbc mapped to old nodes ['3ee132d41dbc']
936 940 30682b960804 mapped to old nodes ['30682b960804']
937 941 e919cdf3d4fe mapped to old nodes ['6bc15dc99efd', 'b50946d5e490']
938 942 D8388 - updated - 15e9b14b4b4c: added file
939 943 D8388 - updated - 6320b7d714cf: one: first commit to review
940 944 D8388 - updated - 3ee132d41dbc: two: second commit to review
941 945 D8388 - updated - 30682b960804: 3: a commit with no detailed message
942 946 D8388 - updated - e919cdf3d4fe: four: extend the fold range
943 947 updating local commit list for D8388
944 948 new commits: ['15e9b14b4b4c', '6320b7d714cf', '3ee132d41dbc', '30682b960804', 'e919cdf3d4fe']
945 949
946 950 $ hg log -r tip -v
947 951 obsolete feature not enabled but 12 markers found!
948 952 changeset: 16:e919cdf3d4fe
949 953 tag: tip
950 954 parent: 11:30682b960804
951 955 user: test
952 956 date: Thu Jan 01 00:00:00 1970 +0000
953 957 files: file2.txt file3.txt
954 958 description:
955 959 four: extend the fold range
956 960
957 961 Differential Revision: https://phab.mercurial-scm.org/D8388
958 962
959 963
960 964
961 965 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now