Repository: helm/helm
Pull request #7176 (2019-12-06 17:13:25)

fix: catch one additional discovery client warning
In comments on #6908 it was suggested that there is a second place where we should catch the discovery client's error. I have not been able to find or reproduce an error that triggers the aforementioned behavior... however, the fix was easy enough.

Can someone who can reproduce the error either (a) provide me a way to reproduce, or (b) test this out and let me know if it fixes the error? *This should not be merged until we know it solves the problem.*

Signed-off-by: Matt Butcher <matt.butcher@microsoft.com>


Patch:
diff --git a/KEYS b/KEYS
index 929938710..95e52f71c 100644
--- a/KEYS
+++ b/KEYS
@@ -622,3 +622,233 @@ BlA4kJPTfla4LmKRg/T/xow/naen/aM9mQCs7k2UAoeqNZ6IfQ6G5BZ81H9JNvHC
 beriLZDBuRy1LJRjBmZEz+UDBgZoR9oz5DOLh8dGVpkt
 =HZO9
 -----END PGP PUBLIC KEY BLOCK-----
+pub   rsa4096 2014-05-13 [SCEA]
+      ABA2529598F6626C420D335B62F49E747D911B60
+uid           [ unknown] Matt Butcher <matt.butcher@microsoft.com>
+sig 3        62F49E747D911B60 2017-08-11  Matt Butcher <matt.butcher@microsoft.com>
+sig          461449C25E36B98E 2018-12-12  Matthew Farina <matt@mattfarina.com>
+sig          1EF612347F8A9958 2018-12-12  Adam Reese <adam@reese.io>
+sig          2CDBBFBB37AE822A 2018-12-12  Adnan Abdulhussein <prydonius@gmail.com>
+uid           [ unknown] technosophos (keybase.io/technosophos) <technosophos@gmail.com>
+sig 3        62F49E747D911B60 2016-10-24  Matt Butcher <matt.butcher@microsoft.com>
+sig          461449C25E36B98E 2018-12-12  Matthew Farina <matt@mattfarina.com>
+sig          1EF612347F8A9958 2018-12-12  Adam Reese <adam@reese.io>
+sig          2CDBBFBB37AE822A 2018-12-12  Adnan Abdulhussein <prydonius@gmail.com>
+uid           [ unknown] keybase.io/technosophos <technosophos@keybase.io>
+sig 3        62F49E747D911B60 2014-05-13  Matt Butcher <matt.butcher@microsoft.com>
+sig          461449C25E36B98E 2018-12-12  Matthew Farina <matt@mattfarina.com>
+sig          1EF612347F8A9958 2018-12-12  Adam Reese <adam@reese.io>
+sig          2CDBBFBB37AE822A 2018-12-12  Adnan Abdulhussein <prydonius@gmail.com>
+sub   rsa2048 2014-05-13 [S] [expires: 2022-05-11]
+sig          62F49E747D911B60 2014-05-13  Matt Butcher <matt.butcher@microsoft.com>
+sub   rsa2048 2014-05-13 [E] [expires: 2022-05-11]
+sig          62F49E747D911B60 2014-05-13  Matt Butcher <matt.butcher@microsoft.com>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: GPGTools - https://gpgtools.org
+
+mQINBFNyROIBEADL6FVlqQPC2DAZS8RGYs9Kiqpu486QI6070Nq1l950XxUdudkm
+dM8TH0FluDkq/RtQQmVHIwBdL4n/pH7EfKTUy4ggYIs9v2VPhMp7DVlRVKIXKoHl
+qQu9I2VI3UNM8j+cQkisFgVrzHi93SHxRKRfJM/qPkQYmzsnBRH/2YAodSOmWybf
+TZJToPtkRXqPMm+ZAAtfyhwvwPiXfSnB3/0t5K4WCdhQP601l3fifyaZVVF9GX3Z
+n54i080HXYhdxr32n8xPi+EDPv7Sh3XuQZ+zmYmSTxZ12mBIZgzwCJH9Uy9XzmE5
+LrZhf/s4mus5VO7ZxqOr/pZ2edzu3Hae9SwVa96kntHK4Oc5Ja6AYK17dibRG7m6
+1AInGbpJ5oJMvm3MwQbxLXtonZuMr3F+ivdBqrnwjpGHiTfeeuBGasx3WIJwBvzv
+94rldvEERAc92eMNEW4G+9tK0w2R8SYP4njWZUKM7ngXRPxA5/vRYj8pzpr/uiFi
+YkkzOTo5beueqdAyqaV7GOG2bmzt2Lc5PSGXK/Ew8sLAiOV4ug2QysNMw2MdjF7v
+ek6Hco8U+Ir5YQnt4B+t9piDg3w45WGdNfAe5roPZtB9yYox6Iy34fo1GmX4qUf7
+3i99UrZ/B+wgCRjHxsqborquMZnX9S0BeQFm2RV/0S2l5A5NT6yHB4B0hwARAQAB
+tD90ZWNobm9zb3Bob3MgKGtleWJhc2UuaW8vdGVjaG5vc29waG9zKSA8dGVjaG5v
+c29waG9zQGdtYWlsLmNvbT6JAjcEEwEKACEFAlgOZHsCGy8FCwkIBwMFFQoJCAsF
+FgIDAQACHgECF4AACgkQYvSedH2RG2DUXhAAtZGIlCFk8GkhxoUFZgcR+AfgKG39
+bcEdDVulGX0r7LpVO3pF0V7KrY/Hz55fVrQjF6UMS6TF4dB/j4U4ylIdv9UUyQUJ
+O9bPJwcYLbSLURqA75NeA7XVSHwvbm6hTCcdnwPxvxkfisd/YUN75mlDNeZEEXs/
+/n+2AxlPX8eQt6n/3RlYYGrekle7EUO8IJcqS8jfSloxkUBO201BubU8lg9bmE4W
+uiav6Dgqs1V4q6jheGz+c6BD/PYOysQiet+1Ot0GscvIKgW0w60q7ilzzviOK3eg
+fiq57W0Oc3GI4ihrfH3ppC3kcJFyAe/zle25QxWHZWfnNZ12ZElK7vIQnl1JzwVb
+sICj+y3j2MUkczHtf4KJZe/7lr1G+No1mFYmDu+GZqT/eSmADOF+IrkoCZgR/jMr
+O9Kgfh5U9B7spbHGkA7eZvH68FHRxqvXnUgBFS5hE9oQyTR2EmBF+hpx8T4K2uIo
+NSCoq5pTD3HNEZqBZ+E1NQCGv1a8YiyLjeI32vljH52pjtfbW06Nfb4rI+/BrMU2
+82gzVHxiN9O5Ba8YmBLbkZYYTW0+9rF5w0brTxRS4IfokNNeanIJ+w7CuUhEyf0O
+yOa0DRxUEvHIq6UFibJWzei2dzBIyHovdIQelkmFr2Oq9LDqsBtSZH5quGzeJ2N/
+atK1HR1GK5CNwRaJAjMEEAEIAB0WIQRnLGV74GtLMJacSldGFEnCXja5jgUCXBE3
+0gAKCRBGFEnCXja5jrJlEACarEjVOWmmZlNkHqajs2rEUJzM+qKThr0QMOd8UvYh
+ZpC0+IPOXLjwXpKiZ+7sPw8YaGHw5NK36jWPy+cPdoDppZfRYHp+/0cmK4GI3DH4
+9x/jW3yG9g8ckYCKYscrhev3AeD1UwjjiiQhS5m15/TTOLPGtu4kcWyeTcdgFMo+
+sdiD1w81XA2/zCTJptsDw8AIxJEk+rqBP46qy7kPpawCsO+x1f17tleZ+5pZPYCu
+G3vuaC9ggcKIp9K2oifH/Qn1YE4G8Dz9KqDsS3Ucg50PR2tpd2nXQCoWatezNxED
+tyNblmx29JJFjSMs9nKNdddDmwWHM8+CNBS9mXRs1BttxtWAPmz2Y/9U4wvQ6V0H
+NxZd3JUItOqxkoxVavdMQrbRDLgI8qVXA9LXABJaJ9SccOJfAK+zJVSVcOqrGoVK
+7jQyBoHsMbbGl4P2EJtFNIUOiAvo+y0cA6oboAYnqgBr3ghOXWa7uiLB2zFhREro
+0VoGlqCjbH6JdvjDcC4Vf9mxtVP42605phBmd6OCDXjTmgn+KToRLKd2i8b/eafZ
+5djwipOpyHHxIQ5N+qSI1jxh+58P8x7502kMTHzCoAdxnWk2CT67Imggby3xh8IM
+jJmvah5NM5a0eFIGZs8HNuhkbtJBuF6WzVoieBbin+O6/7zvNaS3x0ZcYJPZUpWa
+dokCMwQQAQoAHRYhBEnQnIbD3I2j8KB2Ih72EjR/iplYBQJcET/bAAoJEB72EjR/
+iplYOrAP/1b4FsE7QxzYgU2ulBkqDGe9eSWPwuqWORwqpYNPy9UNYKrDn7LO4mfT
+GKvVozfR2e8YjDNsP9PfqPjk7OenqiWkzDgwAZFKoFxbu0RFtxA+aMNVOG6ks6g/
+LJH3uvKxqaK0oUTntB9YusdS5B7JOcSzDo9uw+2mRyavxs7aitJmcMmrU6GySmGu
+t5Nutsr0j1k5vB7lFNu7PYmc/rQyF7UK45+Q5RSzW7lsvudR6VM7qjE+eHfOOB+t
+9Kym2siSrCcwsBsrqGtumXksG3KUFubDr6VG7nUX1y0CkZ8FdtdWnsyssuJy/cUz
+sGhoZIXhnP8LAvVS2/0g5U+94K3TfFPrlhq8Dgt4EWOr8icL13QY1ZhlQNW861KP
+HEOTtUoNJPg7DafrkB377cfwANk8K3iJAMrWK11TR1obr5brMPFvRqeb1OsDeTmf
+PGJkm3DePTKydUNvLwd9FwdG9wsoZVGrn7aRQ59OUn5IdAnuZ5Q9eWnEJf03pTNp
+sJ/6cH4XCLy7bM1iim6oknLKpUFWRFxOgMKVeFNQO1h1D96u21bYDXnbKyc2vlIw
+sBZbKkHsxWr8AzmCOrWb1DTJO5sYTpsBQkQANQt/IUpNbg5eMC7zdyHUpLEyqQ2E
+kfrWOoqoTowXv6xZ7Wdd5/OJHwn4PnsKac4ah3tOMzhQYOAgel+/iQIzBBABCAAd
+FiEEURHac98S2OgSykYvLNu/uzeugioFAlwRQU4ACgkQLNu/uzeugiqARA//YEMd
+eLItDPOCtLlEYJZ9N3VheUA78IER84cena7RDI38Rra7sh5M+msNJJTYH+mXK1B/
+2Y8tIHo870I300vQLLDXXjGDFWuQRDIXgNkVpk8M0msNqtvTps1Pmf7fxpSeI24a
+dGwlyz3oCUELp8bXuyY7LTrNMa8LjNSbS5TdCF0xteuMZdDyD03jDO/fz44Oabtr
+fdaIrzDRbw42AxnzR8wrhlR55+EFxWizWERqPLxhXYYhcGk0PyGdZUzcP9YJmjiV
+h0605ct+ykiIm0RQ5/YGWkKRC8LIRDYW7NB9Hwv62kjw2pSKcOWm9kaGHOjfieCd
+XnBvAPv3sAdcfgx5bP44a2Sh7Bsh8BIqrbsAAG+9b07h7IMM6MCFFxd2smNsp74n
+gPR8k4GF7vfVvZherYCB3EhPLoudoxf/u0Ock2Ssa31XStZ+jHb6a/keEPFGnygg
+opNDfw5BlUsys7wSEDOSTE3cdiE7B0hWxC5Xw80r3SxONk3jPczraSG/EVmKndX9
+quFboecUIXGBbsx79tUolKTMOQrVP7KIM9ltbpvQShy6RYpWa0dKTRuUgMijqiB4
+A1SR5gvVgKs/xzy2Bw9TAH2ayGc/r+mTpwpa6eOhu3NOYhqqkENlZ/IsKnX+dX55
+UvSVexlttUIjxCKjvH61Pmdi8meNhEesjVYnsbS0MWtleWJhc2UuaW8vdGVjaG5v
+c29waG9zIDx0ZWNobm9zb3Bob3NAa2V5YmFzZS5pbz6JAi0EEwEKABcFAlNyROIC
+Gy8DCwkHAxUKCAIeAQIXgAAKCRBi9J50fZEbYCnkD/0WpXKEaTdXwqy7fm87An1H
+H6HcHDR95+Ldu8XgmSZq4nbkDc0wjDdBD5Tp25QSUznzJ4pKO/Wd7l6C4fhqTZn/
+vldDpRXl23bqvRHmWVkXH/EKZxh1y9TnID7Ysy9H9qRVdFm/yjM9EqrD++/vowYW
+Sq6ekosXdjTZWuXVBnirnM/MwSZ/3w1tyK+zfbzA5XR/pscPbTO/UuKdmUbwz4yt
+QjSQg+awJ2iRko0USvDG1t7PyMdDNfF+gbzp6qdI/NUo+XicRzCtmxfKR88vD5yE
+FD0DY/6xl9172XpB3h5aI1jg2LTDLr0IIlO2KHRkqs9piqJuHL8uA870ZMvLJN9g
+JryUny7b5PJlmaYDJPc3TmiMUUHTkrcmJq4Knlh7WtrDX8avbc6T8lWOCakn3cNC
+X3O7RW37k953fF3GSgv8otDlySANW20fG5bPN2gvElfHi4LFP9hAXESZUDYuOasu
+dRUHMkqc9BAMqqgrgrrY9Qmk1aE+udVTcVICRoUoZyBFVzDsRQL+c1zVBk/kJ8oL
+e9cqcdpZbkvVDLtPEyA+b4icX41woqiTRfK28BbKCSwSXkqi+vo9pk9Uwy++S7OS
+D3EOjZhox+Zi2Ijcpzb++B2mxX5yroRrPWvHrxIsAKs8ogO9undz+rJbqgZr1PoF
+rV+wpMe0ckRECvGqEz0BiYkCMwQQAQgAHRYhBGcsZXvga0swlpxKV0YUScJeNrmO
+BQJcETfSAAoJEEYUScJeNrmO1T4P/jAUMiKYNqUlYpCV+mvzVwUQWIyPYdgzqO9R
+AmvI1ELCDT1BGB9pLeeUwFXQX/+8+7lGAVLynL7FPPVkkatblVIQKFgvL7XmU6gb
+o73DpslX6hn+clYeYXUs37XToffVIFVwIQkWusZ+X9BkM2TeV5fgoJ4mhCh8ys5g
+RHKuXYnqCIHfPj033GIhSn1DZRecKPWeb07zYZI4SHsBYEM7xfN4eUEXOjIlRXea
+O6hS6N3vBTinn7LnHkRDD9mUemTruBtab2F9Nk3+njzpafMb4IprD5+GGdRacGOq
+VNWFlZDYyy+3Qv5A7mXBYGCaTtH5Jlz4oEibFXvvVzD3IgwFCvmU1S+UD+9l+u+z
+Nk3F4l07BuulhX6Ek55CoI3kbMCovFjPFrXWghT+/XQy6GaEhQmQ12rhUDBBjS2s
+29NImvHyBGX/FHY0udt4fF/h5O0eRw7zqmGeen4yOu60cEi9MVesRz+GZcbdXupe
+RghrhXhfE6NHcp7ciyK0+Y8f3dpeXVw3na4EOraR4w4ae+SJUt56Sbudqn7S6Kxj
+UCKql68VWHfhh1ibdbv1wl8bAHqtSt0FQlG5mUAcN6R/COO6uK07H2rJWtmIiDAG
+nhcSyLY+5SjD7LtRYvZr+SP2EWQ8wHopjkkGfvG1gXl5NQ8gaVRzErkuc4S3yHMC
+47j+0GsBiQIzBBABCgAdFiEESdCchsPcjaPwoHYiHvYSNH+KmVgFAlwRP9sACgkQ
+HvYSNH+KmVhSoRAArTJp7zUs6pp/+JTFfJsRHbqUBP13KAoZCtaV6auJf+MA6mFD
+TD0DpVKdKBGjKna+W/qFn/8lpIjxL6YtQ3/W1j+d+uhd2OPb44atpXNuxArpCqoZ
+zAyx0ELmgP1YbZ/DIRKv0v0nFsmP4jd14pcclFKGLqh/tK66n3+mOH7zSqltljV0
+9A4evtkI/29/Jj2I31j2rthk+gJmAYiksXVIZb3Hoj4VjFaW0D3/d7Bc5LaUCY2Z
+6GXa208UjBfumKRtSWGXDaz4LmxoS3+H3xfnm3APQIryaSc8daBY0BjDwORa2gUB
+9rddEtSWbVZvJoIdAa7shLvR+eYubMCOjmHc5cV3rG0AF+5pymOv+Z9pAIj8Uzfs
+kXtmIkoXPRfubeb6rNx66fKakgjXqtcGfe0VdYg/VJiheVedPmqBvePFvuUGvROa
+TzDdKxKqi+AR3+JALfcue42xbNCTqWW+iercuKz6gpNukfwuDciNMrH+Ggg8K/FL
+x/NEQbVTA+IFZyuBtiRv37gDNf+gRK1buA1OJg6rS1US8CE/brOWEhSDXN1wJ9wM
+JHtM6xj/Td/L8v7BYOXbq1ffuuXeX7OOa2NF86yTthS+Hx07y6ivaBRIWhf0DA6I
+lQkoKtJJ8dgWtzRgH/Dl18nhgjdqhyaQXnBclxv0B8M3tbpeoJYBRTM/7haJAjME
+EAEIAB0WIQRREdpz3xLY6BLKRi8s27+7N66CKgUCXBFBTQAKCRAs27+7N66CKqz6
+EACB4UuPAH70NzoHo9utcD9bzMj0PRi3GKh6MMm0CsumM360HfN9RftOrB+Y3mjq
+Oyl4onqz4hWKWWQayUsI3T0YiDwtV3zeGkvyKGMB2gZN/duZplHiSj95Jv7HPQRL
+kVo8rrEPboI+EdCCOypZIu8K9vfs/fTrsx14dEy85cOqv4J2is28zOapFoR+79gN
+pErktx0ftcv7e2fxXQB5sUAa8k64bRNuVoFXz1HH6T+7641DwQutGAEFWug/Ythj
+vytNBlcq0bxpzVwC2RAbPrnJdRu8f1XM4jBx9mJz6NfHGvSjEtlAuc53Y9DvJEcZ
+uKwrN2NmtJ0dkO81NaU6B6oT9dwTaJ/6hwHq0WNvPeDcoUZxrh0XXyuhjR/p5MoU
+/0TeiwA6HByO+/wQRL5ZODUag8xlsnXHMxwz6F/mqo6OirJzflJdJkm9kL4UKjCB
+r/jzOmf6WVQEfjWTFmv2empmxT3Z4ahR60DLRCGPlc6v7N7QshbH74b/NfbP7CPt
+SNqQwiPzSTiNjr1SZhMFJ/Zu7HS+/ysXyPw6Ku0s+8zQtkstV9+Oo/mpfm27yDih
+scWIZTmc3RiZmL6eURA9tijdB7ZNuXxTyKkClUfnkiba9zdBCZT+n52zXY9aR4OE
+KEYFXe/x2A2hON02AP/lzgjEpg/3vaSfLrzk0wMeh+yYjLQpTWF0dCBCdXRjaGVy
+IDxtYXR0LmJ1dGNoZXJAbWljcm9zb2Z0LmNvbT6JAk4EEwEKADgWIQSrolKVmPZi
+bEINM1ti9J50fZEbYAUCWY4aMQIbLwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAK
+CRBi9J50fZEbYCtzD/9WqoGpj/rKKoqoToj3hInc3Nv/Nxj9quJc2Z4gxmnwYlB+
+KhZeDlfCytkFFYXgl4bB6KcpnI/OW+hynxR8jT/wIvD5E3wIUCRVJfbdmKBiSha5
+KMDgLGmVpJbVG83s7mN6BlgYPxUa7dFXI43mRBkt9hCnH7U4vwx5rtLlR5FEU6EL
+sjYiWc/zyjqZFLHbnlJ8tt09zKTVDF4SfdJz1vpDCD1exY7LZtsaL1SpE+fuTq+5
+/Z6MvMQk4bJcEbXzrIF1U7C7xIoTv/npv+eb0xdiPto1UKs6C1o2rIdvxbrDc8zz
+pWMRSPjBaOuey01rFKrkpSlxuX1h6HQSDyN2Q7WmeezLh3RgoTwrEnmy/Qi5Ze21
+pi2ygMtUadxTzZRi/IC77s4FOlrnqx27AonEzRQHTtKXhLKrrXD6HQTerf7W9v/l
+24O/QIAdX/JlhYWHQGPHAWe/3o30XkeM/Bhlt29SAnxeWhTo3oa1EudXrAe745eM
+rA/pdAHWgqIBi5KZP0j9nQRtxXN/ZP3ASKjs1CKw4OnwpIWotUkK0XgMemJTgBYR
+FmNUPpUCiLTiZxfJbcQt3khDOfQ53iR3xSLP788MHO5/zGqKcOgnjFlyc8QLdLSb
+db52l79ZaeXamakEEfaZRnR3wtZjWvLk+JnC9nWEVflICnLwKpLoph+ceVe8j4kC
+MwQQAQgAHRYhBGcsZXvga0swlpxKV0YUScJeNrmOBQJcETezAAoJEEYUScJeNrmO
+ZJgP/2yhVoDQbp6T1ngsl079C3ZwyDY//TfKXUwAJJgHo84IdrLWhYYTCo1/2nm5
+rAqmDlq3OJsUMucwj8opocEIBM2HWcRcwFJgwC3Caq6w0vLzmt9Qm5eGIwSPGH/Q
+7w1YQj+6x++xyYuVdmChVIIgQy5TP2cIuM+c+T2Zq2vTGKV6VNKQpVH/o0ymB7zx
+5ZSJdsQGuNWDvZbwsVrYsbbgEy72iO7fVvc3aYUVXL1gvJjAh4GUKApsLWhJGG/G
+HoYvl0PSTpb++HOGwtwbG+GG4ELbISfyrs4JfMUvRA2hd7MZD5BTvO9hzWeFAOJR
+ze5gsDkUCMeJ2D1yoVONHhmaZ8k9xy88p/NOC3iYamoixO6vVkOsCbOhzHRVlj1a
+VV4Zs1RZ6kMgm0HBgGFjj4IjWZy39G+JWfjJuLpRAVOwPv3Km2ertTtJJjkSaTA8
+TRG+/ZjgEse+Gio40aeBhm/2LvM4A1oHe/gzZXQZrHKIl7sy9ijQowj1wuqs+oqz
+gdjjBp/DcU3qbTo0vJ6ACvRjQVcIhIdOypkn31uhUSA1CtHT3TNau4/D+B7YNtWZ
+egeVXWvzFZukXkYzvbDjMn9t3PYHMPKaPYynBGuFPO0fMBXouh4qOfXywFemB+zu
++ccZol3zPzBhdxInOhWi6wjMBSY1zae0S3Co34CSylZ2lu+kiQIzBBABCgAdFiEE
+SdCchsPcjaPwoHYiHvYSNH+KmVgFAlwRP9sACgkQHvYSNH+KmViCHw//dGg9ochq
+Wuh344h8SSqq7G5d+Hch7EIMCykPlDCkmO0/FsKEmMQ2nMySpkm1zM59pHvADlbu
+tbhtLIk8kAjsfyZF2alpTCn1gxRVe/aXBsgmAf/Op2jf92zPkov8bXw7x1oFZ3ew
+fWFR8bwG0OEK8kr9jpkCs2lRv7kG6g60ptsCWDkJGiXpEyovUF0W3ZpCU3RBVUIC
+D8xMTBJXOiCYtux7uDpGJ9iYBGD0eUWxg5OUZs6Gmid2sr+rV4WIoBJEgGUMq37f
+d+loYNwm36GQmU3ytWx3ZduCruNRf5XSdws+nJU0rPb51CiacPp/g9PR/9f9i9/a
+yzao/7pA9/0mfiAXHveK39iNqFH4V0B4hOUzRWWWJJNvZw195LridOcmmgOLTWQJ
+iWErD0VvzZRrf5vf8sdsRoXx1gHrgb2ana3ThfRl+7gE9jgkrEZxGZBh6eaxyxpc
+eTJBtGjcAgATlKSZSrm9ZLI3Jyz+1R+uEj1LPY6rc05c1XU2l6ucoMGRvu/Vs2m6
+XBiyJeqX5yARdVbiTMbmGI39SxoZ4//KJoFjs71+FxT+sZ3syfQyQJjaS8++qB/e
+zmhF4Ab2wh987um42q3Bzl3NXnERFO0Rq5R3ksgBb2ns93Sc6WQPV62pUFxzeHX5
+BcW6vVjL8jkrJuMipKetoZGm5Aimf3oydJ+JAjMEEAEIAB0WIQRREdpz3xLY6BLK
+Ri8s27+7N66CKgUCXBFBTQAKCRAs27+7N66CKrU0D/9tCR/N64xwcY1eq5tEjFb0
+9T0L/aP39hcCOWeMwD2AcA5qSM1Fr/gqCs18db9JqZOcTEISrStzQ/ciGj3Dsnlz
+7LjYVicQjwNK39YxedfAuU1kPAd2k4KujpE8o9b0Q25nsTOth1ZZyXJIIsrywwVS
+CG0shyi2GASuZOXIZOdkYI/SIPojZdQKG8Czd37Lo+2mPDqG5lTL+LUX0UoqEFR0
+AJfsBkZhUodUAJSxzT5sn9ZyBOabAbdFhiwjMHTyvFOdFzIfc5pS+/OqQqdhwxcw
+/FyCFyN5WgC6nRxEZqvW2jbB7xphLPWOWxWbogwD4QACQO6ih6pyUAvkcPGRTJRS
+j9AuJ7cX1iul0hwxjFifoJGnDyNB0oDo7qyfcOQ5lKlYE6BWQiQHcE8UX4pn0Tk8
+z18pSjh79LxFUgKH9Rvv2eIjE0V/GYFh/RiPxopBRGcqnpo4F5mOvLbeNMN/lX2s
+3g8rkpVLa/QWf/d+goak/zVWqLmC/5OMTFnEWrcTu6dVycoEiyfKgf8LRZ4YrSbv
+jkeHNuYwM5KVgv+umLOw/p18mUueYmEvpsmQ55Ri2UxxhNWizm3xEtLo1jLGfBUu
+7RwuZ3AuR8HMBeOHsWe1/MSpZgmbL0V31mfC0M25CrBs0qBUB1QxpCLv+cSa3Acy
+CMfQS9ln8Ydzm2sHPsLZA7kBDQRTckTiAQgA12JICQ4oNax8PaljKomTwuFTCrm4
+6j7Z7HsBM579lqkQmsNaBu8euQF6C5WJUE4aflBIa4Q8vqinZirkdUNvkj2jGdKW
+XG+KwGluvbd8IhCvD9ITV52/Sj0V1PqZMcKktRpEczn1KY5BjILXKbtlp1eVa7Ha
+VMHHge01c2TH6jttOtasUFBkT0jD/Zd4fO6l1e9cN3e7hhIO6HGqcrhNIaHD1ikG
+6VjJU/ndP5qkzwErqlWF2H+TThWaY/PO0zXp5pXQ8geBWPfnw4B6ZvKzoHM54vd+
+aotgoDrNpWMkksm16oAvctXkg/WSt3mzNIHQHQZSYN/uorXek9R8664MmQARAQAB
+iQNEBBgBCgAPBQJTckTiBQkPCZwAAhsCASkJEGL0nnR9kRtgwF0gBBkBCgAGBQJT
+ckTiAAoJENzV9eXvMsNFID4H/j9fGdHyPQLDvH363lsGx62l5zlX1vL8rjleZMTR
+D+JRQJ3MjSgEIdEE8gYLyRmetPsrbQKpOu/uGVs+Ef/SDFj89VhK+661DfHwcahN
+XHPTjcNi6OUlE2Z0DXdxgb4czMZkDf79ga/sf72S1uJNQb83GfYN1QfLq+MXsBmF
+LfYU5RkoF7obgVQFAs5HYf3RqCribdNEhGEZPPG6wNcp5DC1UvrpotldqwHZltFS
+dPPPUT5S/kpcRtqL/bilPc4Pb7qKQR1Huacy1ca1DAEP+TvhvgMmm6ExVAYiV1TA
+ZBfOUYC+Czn7ZOGJ8Q4AN0yno4IOsmwBrxaUx9+38I3rb04nLhAAyUUZZGp4Zfj1
+bJ/pOxZ2H2BqX3fstN9tVvZu47D2DoeF6T6x02HIV7oVQ1/haMnjP7rtsWNjrl32
+RkMkbvwqsnQwcZJrylQTxYuzy4IGXak/tlEcesspsG6O34pvPoZ1c+q92jofPOzl
+W2xnSTtKlt0Fu/m2WNg6s8tfec7emi69J6Pl+XMAmQkihXF+j4QuXYzSV4G97W2t
+AMxo5d3GIQ4UzcxhEvTH5s/S12iGT0xfy6G3yEqTzFgByA94BWN/plzgaaV0bNDs
+uK16Sp6c8gldHs5o5uI9wtJa468dj5Ll9zJZOdC3UN3kGDY1T5jnctnfgLpU081c
+tfz7tr1URFiq2LYlxpEUC/OUFyilHuM17RacLLAM6+9s2bYFD2uAOfQyUJaUD2z2
+/9I7WRaDbL0DMhn/QZPdhLZSMuuoaBEu99NWBGHMfVpDmmPQeBLTS5l4Q7lbrf6f
+zLdb+3Vuhifl6w4UTPC7Wb4qowjtIiaqdtqpsqm2LE62xsvd230wWT+ipGhBx/B4
+soOh2lVXkEGL+nEPTljBxkumkZOTxJl/EC3cFEtVKGCw9Rid8nUmc/v9LcKaJQDO
+AZ0oAMc8eSyxKGaW0pePlHn8k5cds1w2ZsSCXuDGNYHATp4Gm3izEGLRsex1KYq+
++dysRCx2EZMDsaCAUbXNrt12FNhgzh+5AQ0EU3JE4gEIALyimTnOi0q1WouENJKQ
+RlpBsZ25Cxp+kc3Ttws65cFYV+3682KMRelDvZ073JRlyMbEmAsxCitrmsKfI8+9
+3TVg9XS5R9RynMpRiyi1m6sHLbeXG6LaWaT3gyzu9VC6EGoadf+l8/emQD2WeDJl
+fHJr+QivlGM7hdMvjewj7Wp4+x0JclhNsgjYEUkF4ajy/q+A98YyGFybpOwqRoLv
+U5WXQGxuh0LiUjvpLyrIEEFcvASCNOAJgpN92G7nsNDsXpWjwmUDYwM9uJipbM+M
+kyWJykiaii9tYg/AzsFN9Cr0+w07IEX8IfWmY9iGjOC3eISwX/vx/jtrI9Mj8Ei5
+RKUAEQEAAYkDRAQYAQoADwUCU3JE4gUJDwmcAAIbDAEpCRBi9J50fZEbYMBdIAQZ
+AQoABgUCU3JE4gAKCRAZcP/x+neS2tEuB/4tvkwlS/aJJles7+n9gzlcWHeRHECG
+0zTrmQr99uTvBaYewB6gSJK1YrM/ocOH2k6e2EAfYw+bgBXcOpb3NQePZ4vLCAkl
+6J40ktwyWBOs8uCAdBX5Ngkxhiz5oNaxQqnBU+xfovsbQJrxj0S28DBXGDR6npI1
+vqjrsYBoPeo4YZu6pUAp6wW+7eC4eHVK/NIogw0XxA3VRzwvzLK+aUI5RbzyWwYY
+PDfzXrQRqeUqCF2bnnsXjDHxfqjfoWrnK+ATGFZgjbF2wHhPDRRHqAx/ggn8K/R4
+rvhEKFIqxQHrfZgQgsWregiv46Ph8DBEGcniqeIS5kRQi5y71IB7ndb9cB4QAJIb
+BQaB5GhsjVw5bQTsZWMDLoweaR4kqP2eXgx6HuhRw1XcP0ZNNv5//L7tv6tmeXgb
+RO17JzCw8+g2ZFq8Wbd6v9MFKefh+FT75Vvb9jV6h2NtQlteKQ9mpXVpcxZ0pKDb
+hPzrjcI3Xo/zjYHFjTk2VAxWVPtamBN2eCGc3ggWifYnmuCctxHlTZNyDyrfPwJ+
+Vj8VuTsjd/7b8VVLd2lpzF2m9M25z4zNgxzldAAr4F+bIqjPJUVY29pZFyKKqcBG
+zCYBTlB+yiVqjXOyyYQKwE3nkG7UrlsQdQEI/wjqBJtDpQ/w7NLPKwx2633dVQAT
+omPKujL3klFlIdof/5+JUDzmg2mC9ATCJ4sgTAIodo6hHACQT2OuKmAHuCI1oqBs
+7A3H1pPk3HZVKy7LbdQTy7QTzpBiUHklOKWlWj+ugWeABTZZK5U9cm9vq2mT+rcB
+Wu94GriSlDo3vobC78nMDZc68eV18onQpWTlzRsTVVfOjll/8ddtruVkCVhtfRxE
+ANQIfZg7P8oNxVDAX+jIsTDxjh8r+S1wsUQcTNop6JMicDbxrBRB13vYIY0Jg4+Z
+9WUiKCaM69kbgcJ7tTp0skcJ+rYcjVkTz2/P33/FA8BMDUwCR2FovRnmq9pVjAAP
+hS0eN8yqaR533ire0Ur5Vif6+z4A0ifVTZ2hY96B
+=nEJu
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/Makefile b/Makefile
index e48a20fd5..31e1f4374 100644
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,15 @@
-BINDIR     := $(CURDIR)/bin
-DIST_DIRS  := find * -type d -exec
-TARGETS    := darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le windows/amd64
-BINNAME    ?= helm
+BINDIR      := $(CURDIR)/bin
+DIST_DIRS   := find * -type d -exec
+TARGETS     := darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le linux/s390x windows/amd64
+TARGET_OBJS ?= darwin-amd64.tar.gz darwin-amd64.tar.gz.sha256 linux-amd64.tar.gz linux-amd64.tar.gz.sha256 linux-386.tar.gz linux-386.tar.gz.sha256 linux-arm.tar.gz linux-arm.tar.gz.sha256 linux-arm64.tar.gz linux-arm64.tar.gz.sha256 linux-ppc64le.tar.gz linux-ppc64le.tar.gz.sha256 linux-s390x.tar.gz linux-s390x.tar.gz.sha256 windows-amd64.zip windows-amd64.zip.sha256
+BINNAME     ?= helm
 
 GOPATH        = $(shell go env GOPATH)
 DEP           = $(GOPATH)/bin/dep
 GOX           = $(GOPATH)/bin/gox
 GOIMPORTS     = $(GOPATH)/bin/goimports
 
-ACCEPTANCE_DIR:=$(GOPATH)/src/helm.sh/acceptance-testing
+ACCEPTANCE_DIR:=../acceptance-testing
 # To specify the subset of acceptance tests to run. '.' means all tests
 ACCEPTANCE_RUN_TESTS=.
 
@@ -138,6 +139,20 @@ dist:
 		$(DIST_DIRS) zip -r helm-${VERSION}-{}.zip {} \; \
 	)
 
+.PHONY: fetch-dist
+fetch-dist:
+	mkdir -p _dist
+	cd _dist && \
+	for obj in ${TARGET_OBJS} ; do \
+		curl -sSL -o helm-${VERSION}-$${obj} https://get.helm.sh/helm-${VERSION}-$${obj} ; \
+	done
+
+.PHONY: sign
+sign:
+	for f in _dist/*.{gz,zip,sha256} ; do \
+		gpg --armor --detach-sign $${f} ; \
+	done
+
 .PHONY: checksum
 checksum:
 	for f in _dist/*.{gz,zip} ; do \
diff --git a/OWNERS b/OWNERS
index 715c8993d..d7dac5514 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,6 +4,7 @@ maintainers:
   - fibonacci1729
   - hickeyma
   - jdolitsky
+  - marckhouzam
   - mattfarina
   - michelleN
   - prydonius
diff --git a/README.md b/README.md
index 73fd189d7..745a60c2b 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Helm is a tool for managing Charts. Charts are packages of pre-configured Kubern
 
 Use Helm to:
 
-- Find and use [popular software packaged as Helm Charts](https://github.com/helm/charts) to run in Kubernetes
+- Find and use [popular software packaged as Helm Charts](https://hub.helm.sh) to run in Kubernetes
 - Share your own applications as Helm Charts
 - Create reproducible builds of your Kubernetes applications
 - Intelligently manage your Kubernetes manifest files
diff --git a/cmd/helm/env.go b/cmd/helm/env.go
index 1b9cb4012..2687272ba 100644
--- a/cmd/helm/env.go
+++ b/cmd/helm/env.go
@@ -19,6 +19,7 @@ package main
 import (
 	"fmt"
 	"io"
+	"sort"
 
 	"helm.sh/helm/v3/pkg/cli"
 
@@ -55,8 +56,18 @@ type envOptions struct {
 }
 
 func (o *envOptions) run(out io.Writer) error {
-	for k, v := range o.settings.EnvVars() {
-		fmt.Printf("%s=\"%s\"\n", k, v)
+	envVars := o.settings.EnvVars()
+
+	// Sort the variables by alphabetical order.
+	// This allows for a constant output across calls to 'helm env'.
+	var keys []string
+	for k := range envVars {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+
+	for _, k := range keys {
+		fmt.Printf("%s=\"%s\"\n", k, envVars[k])
 	}
 	return nil
 }
diff --git a/cmd/helm/flags.go b/cmd/helm/flags.go
index 467abbd6e..aa22603f4 100644
--- a/cmd/helm/flags.go
+++ b/cmd/helm/flags.go
@@ -31,7 +31,7 @@ import (
 const outputFlag = "output"
 
 func addValueOptionsFlags(f *pflag.FlagSet, v *values.Options) {
-	f.StringSliceVarP(&v.ValueFiles, "values", "f", []string{}, "specify values in a YAML file or a URL(can specify multiple)")
+	f.StringSliceVarP(&v.ValueFiles, "values", "f", []string{}, "specify values in a YAML file or a URL (can specify multiple)")
 	f.StringArrayVar(&v.Values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
 	f.StringArrayVar(&v.StringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
 	f.StringArrayVar(&v.FileValues, "set-file", []string{}, "set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)")
diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go
index 2c3c9e401..112d5123f 100644
--- a/cmd/helm/helm.go
+++ b/cmd/helm/helm.go
@@ -68,8 +68,7 @@ func main() {
 	cmd := newRootCmd(actionConfig, os.Stdout, os.Args[1:])
 
 	if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), os.Getenv("HELM_DRIVER"), debug); err != nil {
-		debug("%+v", err)
-		os.Exit(1)
+		log.Fatal(err)
 	}
 
 	if err := cmd.Execute(); err != nil {
diff --git a/cmd/helm/install.go b/cmd/helm/install.go
index 0c14c013b..b75dfce74 100644
--- a/cmd/helm/install.go
+++ b/cmd/helm/install.go
@@ -17,6 +17,7 @@ limitations under the License.
 package main
 
 import (
+	"fmt"
 	"io"
 	"time"
 
@@ -135,6 +136,7 @@ func addInstallFlags(f *pflag.FlagSet, client *action.Install, valueOpts *values
 	f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout")
 	f.BoolVarP(&client.GenerateName, "generate-name", "g", false, "generate the name (and omit the NAME parameter)")
 	f.StringVar(&client.NameTemplate, "name-template", "", "specify template used to name the release")
+	f.StringVar(&client.Description, "description", "", "add a custom description")
 	f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored")
 	f.BoolVar(&client.DependencyUpdate, "dependency-update", false, "run helm dependency update before installing the chart")
 	f.BoolVar(&client.Atomic, "atomic", false, "if set, installation process purges chart on fail. The --wait flag will be set automatically if --atomic is used")
@@ -181,6 +183,10 @@ func runInstall(args []string, client *action.Install, valueOpts *values.Options
 		return nil, err
 	}
 
+	if chartRequested.Metadata.Deprecated {
+		fmt.Fprintln(out, "WARNING: This chart is deprecated")
+	}
+
 	if req := chartRequested.Metadata.Dependencies; req != nil {
 		// If CheckDependencies returns an error, we have unfulfilled dependencies.
 		// As of Helm 2.4.0, this is treated as a stopping condition:
diff --git a/cmd/helm/list.go b/cmd/helm/list.go
index 0da0c21d3..57fc4be3c 100644
--- a/cmd/helm/list.go
+++ b/cmd/helm/list.go
@@ -32,7 +32,7 @@ import (
 )
 
 var listHelp = `
-This command lists all of the releases.
+This command lists all of the releases for a specified namespace (uses current namespace context if namespace not specified).
 
 By default, it lists only releases that are deployed or failed. Flags like
 '--uninstalled' and '--all' will alter this behavior. Such flags can be combined:
@@ -96,7 +96,7 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 	f.BoolVarP(&client.Short, "short", "q", false, "output short (quiet) listing format")
 	f.BoolVarP(&client.ByDate, "date", "d", false, "sort by release date")
 	f.BoolVarP(&client.SortReverse, "reverse", "r", false, "reverse the sort order")
-	f.BoolVarP(&client.All, "all", "a", false, "show all releases, not just the ones marked deployed or failed")
+	f.BoolVarP(&client.All, "all", "a", false, "show all releases without any filter applied")
 	f.BoolVar(&client.Uninstalled, "uninstalled", false, "show uninstalled releases (if 'helm uninstall --keep-history' was used)")
 	f.BoolVar(&client.Superseded, "superseded", false, "show superseded releases")
 	f.BoolVar(&client.Uninstalling, "uninstalling", false, "show releases that are currently being uninstalled")
diff --git a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go
index 1c84ad8d6..e6afce3d5 100644
--- a/cmd/helm/repo_add.go
+++ b/cmd/helm/repo_add.go
@@ -29,7 +29,7 @@ import (
 	"github.com/gofrs/flock"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
-	"gopkg.in/yaml.v2"
+	"sigs.k8s.io/yaml"
 
 	"helm.sh/helm/v3/cmd/helm/require"
 	"helm.sh/helm/v3/pkg/getter"
diff --git a/cmd/helm/repo_remove.go b/cmd/helm/repo_remove.go
index c1ecb1829..ea7a5db24 100644
--- a/cmd/helm/repo_remove.go
+++ b/cmd/helm/repo_remove.go
@@ -76,7 +76,12 @@ func (o *repoRemoveOptions) run(out io.Writer) error {
 }
 
 func removeRepoCache(root, name string) error {
-	idx := filepath.Join(root, helmpath.CacheIndexFile(name))
+	idx := filepath.Join(root, helmpath.CacheChartsFile(name))
+	if _, err := os.Stat(idx); err == nil {
+		os.Remove(idx)
+	}
+
+	idx = filepath.Join(root, helmpath.CacheIndexFile(name))
 	if _, err := os.Stat(idx); os.IsNotExist(err) {
 		return nil
 	} else if err != nil {
diff --git a/cmd/helm/root.go b/cmd/helm/root.go
index f0a034d45..bba3ff643 100644
--- a/cmd/helm/root.go
+++ b/cmd/helm/root.go
@@ -64,12 +64,12 @@ __helm_override_flags_to_kubectl_flags()
     # --kubeconfig, -n, --namespace stay the same for kubectl
     # --kube-context becomes --context for kubectl
     __helm_debug "${FUNCNAME[0]}: flags to convert: $1"
-    echo "$1" | sed s/kube-context/context/
+    echo "$1" | \sed s/kube-context/context/
 }
 
 __helm_get_repos()
 {
-    eval $(__helm_binary_name) repo list 2>/dev/null | tail +2 | cut -f1
+    eval $(__helm_binary_name) repo list 2>/dev/null | \tail -n +2 | \cut -f1
 }
 
 __helm_get_contexts()
@@ -125,7 +125,7 @@ __helm_zsh_comp_nospace() {
     # We only do this if there is a single choice left for completion
     # to reduce the times the user could be presented with the fake completion choice.
 
-    out=($(echo ${in[*]} | tr " " "\n" | \grep "^${cur}"))
+    out=($(echo ${in[*]} | \tr " " "\n" | \grep "^${cur}"))
     __helm_debug "${FUNCNAME[0]}: out is ${out[*]}"
 
     [ ${#out[*]} -eq 1 ] && out+=("${out}.")
@@ -139,13 +139,25 @@ __helm_zsh_comp_nospace() {
 __helm_list_charts()
 {
     __helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
-    local repo url file out=() nospace=0 wantFiles=$1
+    local prefix chart repo url file out=() nospace=0 wantFiles=$1
 
     # Handle completions for repos
     for repo in $(__helm_get_repos); do
         if [[ "${cur}" =~ ^${repo}/.* ]]; then
             # We are doing completion from within a repo
-            out=$(eval $(__helm_binary_name) search repo ${cur} 2>/dev/null | cut -f1 | \grep ^${cur})
+            local cacheFile=$(eval $(__helm_binary_name) env 2>/dev/null | \grep HELM_REPOSITORY_CACHE | \cut -d= -f2 | \sed s/\"//g)/${repo}-charts.txt
+            if [ -f "$cacheFile" ]; then
+                # Get the list of charts from the cached file
+                prefix=${cur#${repo}/}
+                for chart in $(\grep ^$prefix $cacheFile); do
+                    out+=(${repo}/${chart})
+                done
+            else
+                # If there is no cached list file, fallback to helm search, which is much slower
+                # This will happen after the caching feature is first installed but before the user
+                # does a 'helm repo update' to generate the cached list file.
+				out=$(eval $(__helm_binary_name) search repo ${cur} 2>/dev/null | \cut -f1 | \grep ^${cur})
+            fi
             nospace=0
         elif [[ ${repo} =~ ^${cur}.* ]]; then
             # We are completing a repo name
@@ -236,7 +248,7 @@ __helm_list_plugins()
     __helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
     local out
     # Use eval in case helm_binary_name contains a variable (e.g., $HOME/bin/h3)
-    if out=$(eval $(__helm_binary_name) plugin list 2>/dev/null | tail +2 | cut -f1); then
+    if out=$(eval $(__helm_binary_name) plugin list 2>/dev/null | \tail -n +2 | \cut -f1); then
         COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
     fi
 }
@@ -418,7 +430,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
 		registry.ClientOptWriter(out),
 	)
 	if err != nil {
-		// TODO: dont panic here, refactor newRootCmd to return error
+		// TODO: don't panic here, refactor newRootCmd to return error
 		panic(err)
 	}
 	actionConfig.RegistryClient = registryClient
diff --git a/cmd/helm/status.go b/cmd/helm/status.go
index 92e12dbe0..92a947c26 100644
--- a/cmd/helm/status.go
+++ b/cmd/helm/status.go
@@ -31,12 +31,13 @@ import (
 	"helm.sh/helm/v3/pkg/release"
 )
 
+// NOTE: Keep the list of statuses up-to-date with pkg/release/status.go.
 var statusHelp = `
 This command shows the status of a named release.
 The status consists of:
 - last deployment time
 - k8s namespace in which the release lives
-- state of the release (can be: unknown, deployed, deleted, superseded, failed or deleting)
+- state of the release (can be: unknown, deployed, uninstalled, superseded, failed, uninstalling, pending-install, pending-upgrade or pending-rollback)
 - list of resources that this release consists of, sorted by kind
 - details on last test suite run, if applicable
 - additional notes provided by the chart
diff --git a/cmd/helm/template.go b/cmd/helm/template.go
index b660cc69f..a47631c0d 100644
--- a/cmd/helm/template.go
+++ b/cmd/helm/template.go
@@ -129,6 +129,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 	f.StringVar(&client.OutputDir, "output-dir", "", "writes the executed templates to files in output-dir instead of stdout")
 	f.BoolVar(&validate, "validate", false, "validate your manifests against the Kubernetes cluster you are currently pointing at. This is the same validation performed on an install")
 	f.BoolVar(&includeCrds, "include-crds", false, "include CRDs in the templated output")
+	f.BoolVar(&client.IsUpgrade, "is-upgrade", false, "set .Release.IsUpgrade instead of .Release.IsInstall")
 	f.StringArrayVarP(&extraAPIs, "api-versions", "a", []string{}, "Kubernetes api versions used for Capabilities.APIVersions")
 
 	return cmd
diff --git a/cmd/helm/testdata/testcharts/object-order/values.yaml b/cmd/helm/testdata/testcharts/object-order/values.yaml
new file mode 100644
index 000000000..e69de29bb
diff --git a/cmd/helm/uninstall.go b/cmd/helm/uninstall.go
index 27b5a8426..7096d7873 100644
--- a/cmd/helm/uninstall.go
+++ b/cmd/helm/uninstall.go
@@ -69,6 +69,7 @@ func newUninstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 	f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during uninstallation")
 	f.BoolVar(&client.KeepHistory, "keep-history", false, "remove all associated resources and mark the release as deleted, but retain the release history")
 	f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)")
+	f.StringVar(&client.Description, "description", "", "add a custom description")
 
 	return cmd
 }
diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go
index eadc3b63d..acfc23198 100644
--- a/cmd/helm/upgrade.go
+++ b/cmd/helm/upgrade.go
@@ -127,6 +127,10 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 				}
 			}
 
+			if ch.Metadata.Deprecated {
+				fmt.Fprintln(out, "WARNING: This chart is deprecated")
+			}
+
 			rel, err := client.Run(args[0], ch, vals)
 			if err != nil {
 				return errors.Wrap(err, "UPGRADE FAILED")
@@ -156,6 +160,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 	f.IntVar(&client.MaxHistory, "history-max", 10, "limit the maximum number of revisions saved per release. Use 0 for no limit")
 	f.BoolVar(&client.CleanupOnFail, "cleanup-on-fail", false, "allow deletion of new resources created in this upgrade when upgrade fails")
 	f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent")
+	f.StringVar(&client.Description, "description", "", "add a custom description")
 	addChartPathOptionsFlags(f, &client.ChartPathOptions)
 	addValueOptionsFlags(f, valueOpts)
 	bindOutputFlag(cmd, &outfmt)
diff --git a/cmd/helm/verify.go b/cmd/helm/verify.go
index 1cdd26290..d3ae517c9 100644
--- a/cmd/helm/verify.go
+++ b/cmd/helm/verify.go
@@ -27,7 +27,7 @@ import (
 const verifyDesc = `
 Verify that the given chart has a valid provenance file.
 
-Provenance files provide crytographic verification that a chart has not been
+Provenance files provide cryptographic verification that a chart has not been
 tampered with, and was packaged by a trusted provider.
 
 This command can be used to verify a local chart. Several other commands provide
diff --git a/go.mod b/go.mod
index 57b342ed2..ed074074d 100644
--- a/go.mod
+++ b/go.mod
@@ -5,8 +5,8 @@ go 1.13
 require (
 	github.com/BurntSushi/toml v0.3.1
 	github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e // indirect
-	github.com/Masterminds/semver/v3 v3.0.1
-	github.com/Masterminds/sprig/v3 v3.0.0
+	github.com/Masterminds/semver/v3 v3.0.3
+	github.com/Masterminds/sprig/v3 v3.0.2
 	github.com/Masterminds/vcs v1.13.0
 	github.com/Microsoft/go-winio v0.4.12 // indirect
 	github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a
@@ -59,7 +59,6 @@ require (
 	google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect
 	google.golang.org/grpc v1.24.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
-	gopkg.in/yaml.v2 v2.2.4
 	k8s.io/api v0.0.0-20191016110408-35e52d86657a
 	k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65
 	k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8
diff --git a/go.sum b/go.sum
index 5659b06f8..629d466c2 100644
--- a/go.sum
+++ b/go.sum
@@ -25,10 +25,10 @@ github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e h1:eb0Pzkt15Bm
 github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
 github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
 github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/semver/v3 v3.0.1 h1:2kKm5lb7dKVrt5TYUiAavE6oFc1cFT0057UVGT+JqLk=
-github.com/Masterminds/semver/v3 v3.0.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
-github.com/Masterminds/sprig/v3 v3.0.0 h1:KSQz7Nb08/3VU9E4ns29dDxcczhOD1q7O1UfM4G3t3g=
-github.com/Masterminds/sprig/v3 v3.0.0/go.mod h1:NEUY/Qq8Gdm2xgYA+NwJM6wmfdRV9xkh8h/Rld20R0U=
+github.com/Masterminds/semver/v3 v3.0.3 h1:znjIyLfpXEDQjOIEWh+ehwpTU14UzUPub3c3sm36u14=
+github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Masterminds/sprig/v3 v3.0.2 h1:wz22D0CiSctrliXiI9ZO3HoNApweeRGftyDN+BQa3B8=
+github.com/Masterminds/sprig/v3 v3.0.2/go.mod h1:oesJ8kPONMONaZgtiHNzUShJbksypC5kWczhZAf6+aU=
 github.com/Masterminds/vcs v1.13.0 h1:USF5TvZGYgIpcbNAEMLfFhHqP08tFZVlUVrmTSpqnyA=
 github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
 github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
diff --git a/internal/experimental/registry/util.go b/internal/experimental/registry/util.go
index 3a4589d01..697a890e3 100644
--- a/internal/experimental/registry/util.go
+++ b/internal/experimental/registry/util.go
@@ -49,7 +49,7 @@ func shortDigest(digest string) string {
 	return digest
 }
 
-// timeAgo returns a human-readable timestamp respresenting time that has passed
+// timeAgo returns a human-readable timestamp representing time that has passed
 func timeAgo(t time.Time) string {
 	return units.HumanDuration(time.Now().UTC().Sub(t))
 }
diff --git a/internal/ignore/rules.go b/internal/ignore/rules.go
index c9aaeacca..9049aff0d 100644
--- a/internal/ignore/rules.go
+++ b/internal/ignore/rules.go
@@ -73,7 +73,7 @@ func Parse(file io.Reader) (*Rules, error) {
 	return r, s.Err()
 }
 
-// Ignore evalutes the file at the given path, and returns true if it should be ignored.
+// Ignore evaluates the file at the given path, and returns true if it should be ignored.
 //
 // Ignore evaluates path against the rules in order. Evaluation stops when a match
 // is found. Matching a negative rule will stop evaluation.
diff --git a/internal/monocular/search.go b/internal/monocular/search.go
index 61695f554..10e1f2136 100644
--- a/internal/monocular/search.go
+++ b/internal/monocular/search.go
@@ -58,7 +58,7 @@ type Chart struct {
 	Icon        string             `json:"icon"`
 }
 
-// Repo contains the name in monocular the the url for the repository
+// Repo contains the name in monocular the url for the repository
 type Repo struct {
 	Name string `json:"name"`
 	URL  string `json:"url"`
diff --git a/internal/version/version.go b/internal/version/version.go
index 131a2b130..22439d11b 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -33,7 +33,7 @@ var (
 	version = "v3.0"
 
 	// metadata is extra build time data
-	metadata = "unreleased"
+	metadata = ""
 	// gitCommit is the git sha1
 	gitCommit = ""
 	// gitTreeState is the state of the git tree
diff --git a/pkg/action/action.go b/pkg/action/action.go
index f74a25e41..9405cc401 100644
--- a/pkg/action/action.go
+++ b/pkg/action/action.go
@@ -66,7 +66,7 @@ var ValidName = regexp.MustCompile("^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+
 
 // Configuration injects the dependencies that all actions share.
 type Configuration struct {
-	// RESTClientGetter is an interface that loads Kuberbetes clients.
+	// RESTClientGetter is an interface that loads Kubernetes clients.
 	RESTClientGetter RESTClientGetter
 
 	// Releases stores records of releases.
@@ -167,8 +167,8 @@ func (c *Configuration) releaseContent(name string, version int) (*release.Relea
 // GetVersionSet retrieves a set of available k8s API versions
 func GetVersionSet(client discovery.ServerResourcesInterface) (chartutil.VersionSet, error) {
 	groups, resources, err := client.ServerGroupsAndResources()
-	if err != nil {
-		return chartutil.DefaultVersionSet, err
+	if err != nil && !discovery.IsGroupDiscoveryFailedError(err) {
+		return chartutil.DefaultVersionSet, errors.Wrap(err, "could not get apiVersions from Kubernetes")
 	}
 
 	// FIXME: The Kubernetes test fixture for cli appears to always return nil
diff --git a/pkg/action/install.go b/pkg/action/install.go
index 8cd270693..292a7ec27 100644
--- a/pkg/action/install.go
+++ b/pkg/action/install.go
@@ -79,6 +79,7 @@ type Install struct {
 	ReleaseName      string
 	GenerateName     bool
 	NameTemplate     string
+	Description      string
 	OutputDir        string
 	Atomic           bool
 	SkipCRDs         bool
@@ -86,6 +87,8 @@ type Install struct {
 	// APIVersions allows a manual set of supported API Versions to be passed
 	// (for things like templating). These are ignored if ClientOnly is false
 	APIVersions chartutil.VersionSet
+	// Used by helm template to render charts with .Release.IsUpgrade. Ignored if Dry-Run is false
+	IsUpgrade bool
 }
 
 // ChartPathOptions captures common options used for controlling chart paths
@@ -197,11 +200,14 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
 		return nil, err
 	}
 
+	//special case for helm template --is-upgrade
+	isUpgrade := i.IsUpgrade && i.DryRun
 	options := chartutil.ReleaseOptions{
 		Name:      i.ReleaseName,
 		Namespace: i.Namespace,
 		Revision:  1,
-		IsInstall: true,
+		IsInstall: !isUpgrade,
+		IsUpgrade: isUpgrade,
 	}
 	valuesToRender, err := chartutil.ToRenderValues(chrt, vals, options, caps)
 	if err != nil {
@@ -237,7 +243,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
 	// we'll end up in a state where we will delete those resources upon
 	// deleting the release because the manifest will be pointing at that
 	// resource
-	if !i.ClientOnly {
+	if !i.ClientOnly && !isUpgrade {
 		if err := existingResourceConflict(resources); err != nil {
 			return nil, errors.Wrap(err, "rendered manifests contain a resource that already exists. Unable to continue with install")
 		}
@@ -292,7 +298,11 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
 		}
 	}
 
-	rel.SetStatus(release.StatusDeployed, "Install complete")
+	if len(i.Description) > 0 {
+		rel.SetStatus(release.StatusDeployed, i.Description)
+	} else {
+		rel.SetStatus(release.StatusDeployed, "Install complete")
+	}
 
 	// This is a tricky case. The release has been created, but the result
 	// cannot be recorded. The truest thing to tell the user is that the
@@ -426,8 +436,20 @@ func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values
 		}
 	}
 
-	files, err := engine.Render(ch, values)
-	if err != nil {
+	var files map[string]string
+	var err2 error
+
+	if c.RESTClientGetter != nil {
+		rest, err := c.RESTClientGetter.ToRESTConfig()
+		if err != nil {
+			return hs, b, "", err
+		}
+		files, err2 = engine.RenderWithClient(ch, values, rest)
+	} else {
+		files, err2 = engine.Render(ch, values)
+	}
+
+	if err2 != nil {
 		return hs, b, "", err
 	}
 
@@ -545,6 +567,10 @@ func (i *Install) NameAndChart(args []string) (string, string, error) {
 		return nil
 	}
 
+	if len(args) > 2 {
+		return args[0], args[1], errors.Errorf("expected at most two arguments, unexpected arguments: %v", strings.Join(args[2:], ", "))
+	}
+
 	if len(args) == 2 {
 		return args[0], args[1], flagsNotSet()
 	}
diff --git a/pkg/action/list.go b/pkg/action/list.go
index 4af0ef8e5..5d3417203 100644
--- a/pkg/action/list.go
+++ b/pkg/action/list.go
@@ -41,7 +41,7 @@ const (
 	ListPendingInstall
 	// ListPendingUpgrade filters on status "pending_upgrade" (upgrade in progress)
 	ListPendingUpgrade
-	// ListPendingRollback filters on status "pending_rollback" (rollback in progres)
+	// ListPendingRollback filters on status "pending_rollback" (rollback in progress)
 	ListPendingRollback
 	// ListSuperseded filters on status "superseded" (historical release version that is no longer deployed)
 	ListSuperseded
diff --git a/pkg/action/pull.go b/pkg/action/pull.go
index b0a3d2598..4ff5f5c3e 100644
--- a/pkg/action/pull.go
+++ b/pkg/action/pull.go
@@ -110,13 +110,21 @@ func (p *Pull) Run(chartRef string) (string, error) {
 		if !filepath.IsAbs(ud) {
 			ud = filepath.Join(p.DestDir, ud)
 		}
-		if fi, err := os.Stat(ud); err != nil {
-			if err := os.MkdirAll(ud, 0755); err != nil {
+		// Let udCheck to check conflict file/dir without replacing ud when untarDir is the current directory(.).
+		udCheck := ud
+		if udCheck == "." {
+			_, udCheck = filepath.Split(chartRef)
+		} else {
+			_, chartName := filepath.Split(chartRef)
+			udCheck = filepath.Join(udCheck, chartName)
+		}
+		if _, err := os.Stat(udCheck); err != nil {
+			if err := os.MkdirAll(udCheck, 0755); err != nil {
 				return out.String(), errors.Wrap(err, "failed to untar (mkdir)")
 			}
 
-		} else if !fi.IsDir() {
-			return out.String(), errors.Errorf("failed to untar: %s is not a directory", ud)
+		} else {
+			return out.String(), errors.Errorf("failed to untar: a file or directory with the name %s already exists", udCheck)
 		}
 
 		return out.String(), chartutil.ExpandFile(ud, saved)
diff --git a/pkg/action/uninstall.go b/pkg/action/uninstall.go
index fb72a845b..dfaa98472 100644
--- a/pkg/action/uninstall.go
+++ b/pkg/action/uninstall.go
@@ -37,6 +37,7 @@ type Uninstall struct {
 	DryRun       bool
 	KeepHistory  bool
 	Timeout      time.Duration
+	Description  string
 }
 
 // NewUninstall creates a new Uninstall object with the given configuration.
@@ -118,7 +119,11 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error)
 	}
 
 	rel.Info.Status = release.StatusUninstalled
-	rel.Info.Description = "Uninstallation complete"
+	if len(u.Description) > 0 {
+		rel.Info.Description = u.Description
+	} else {
+		rel.Info.Description = "Uninstallation complete"
+	}
 
 	if !u.KeepHistory {
 		u.cfg.Log("purge requested for %s", name)
diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go
index d0495a864..cdc40eaaa 100644
--- a/pkg/action/upgrade.go
+++ b/pkg/action/upgrade.go
@@ -58,6 +58,7 @@ type Upgrade struct {
 	Atomic        bool
 	CleanupOnFail bool
 	SubNotes      bool
+	Description   string
 }
 
 // NewUpgrade creates a new Upgrade object with the given configuration.
@@ -218,7 +219,11 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
 
 	if u.DryRun {
 		u.cfg.Log("dry run for %s", upgradedRelease.Name)
-		upgradedRelease.Info.Description = "Dry run complete"
+		if len(u.Description) > 0 {
+			upgradedRelease.Info.Description = u.Description
+		} else {
+			upgradedRelease.Info.Description = "Dry run complete"
+		}
 		return upgradedRelease, nil
 	}
 
@@ -270,7 +275,11 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
 	u.cfg.recordRelease(originalRelease)
 
 	upgradedRelease.Info.Status = release.StatusDeployed
-	upgradedRelease.Info.Description = "Upgrade complete"
+	if len(u.Description) > 0 {
+		upgradedRelease.Info.Description = u.Description
+	} else {
+		upgradedRelease.Info.Description = "Upgrade complete"
+	}
 
 	return upgradedRelease, nil
 }
diff --git a/pkg/action/validate.go b/pkg/action/validate.go
index 526a4c7fc..6bbfc5e8d 100644
--- a/pkg/action/validate.go
+++ b/pkg/action/validate.go
@@ -33,7 +33,8 @@ func existingResourceConflict(resources kube.ResourceList) error {
 		}
 
 		helper := resource.NewHelper(info.Client, info.Mapping)
-		if _, err := helper.Get(info.Namespace, info.Name, info.Export); err != nil {
+		existing, err := helper.Get(info.Namespace, info.Name, info.Export)
+		if err != nil {
 			if apierrors.IsNotFound(err) {
 				return nil
 			}
@@ -41,7 +42,7 @@ func existingResourceConflict(resources kube.ResourceList) error {
 			return errors.Wrap(err, "could not get information about the resource")
 		}
 
-		return fmt.Errorf("existing resource conflict: kind: %s, namespace: %s, name: %s", info.Mapping.GroupVersionKind.Kind, info.Namespace, info.Name)
+		return fmt.Errorf("existing resource conflict: namespace: %s, name: %s, existing_kind: %s, new_kind: %s", info.Namespace, info.Name, existing.GetObjectKind().GroupVersionKind(), info.Mapping.GroupVersionKind)
 	})
 	return err
 }
diff --git a/pkg/chart/dependency.go b/pkg/chart/dependency.go
index 0837f8d19..9ec4544c2 100644
--- a/pkg/chart/dependency.go
+++ b/pkg/chart/dependency.go
@@ -53,7 +53,7 @@ type Dependency struct {
 //
 // It represents the state that the dependencies should be in.
 type Lock struct {
-	// Genderated is the date the lock file was last generated.
+	// Generated is the date the lock file was last generated.
 	Generated time.Time `json:"generated"`
 	// Digest is a hash of the dependencies in Chart.yaml.
 	Digest string `json:"digest"`
diff --git a/pkg/chart/loader/load.go b/pkg/chart/loader/load.go
index 3c38519bc..dd4fd2dff 100644
--- a/pkg/chart/loader/load.go
+++ b/pkg/chart/loader/load.go
@@ -114,12 +114,18 @@ func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
 			if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil {
 				return c, errors.Wrap(err, "cannot load requirements.yaml")
 			}
+			if c.Metadata.APIVersion == chart.APIVersionV1 {
+				c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
+			}
 		// Deprecated: requirements.lock is deprecated use Chart.lock.
 		case f.Name == "requirements.lock":
 			c.Lock = new(chart.Lock)
 			if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil {
 				return c, errors.Wrap(err, "cannot load requirements.lock")
 			}
+			if c.Metadata.APIVersion == chart.APIVersionV1 {
+				c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
+			}
 
 		case strings.HasPrefix(f.Name, "templates/"):
 			c.Templates = append(c.Templates, &chart.File{Name: f.Name, Data: f.Data})
diff --git a/pkg/chartutil/chartfile.go b/pkg/chartutil/chartfile.go
index 68176ed5d..808a902b1 100644
--- a/pkg/chartutil/chartfile.go
+++ b/pkg/chartutil/chartfile.go
@@ -42,7 +42,16 @@ func LoadChartfile(filename string) (*chart.Metadata, error) {
 //
 // 'filename' should be the complete path and filename ('foo/Chart.yaml')
 func SaveChartfile(filename string, cf *chart.Metadata) error {
+	// Pull out the dependencies of a v1 Chart, since there's no way
+	// to tell the serializer to skip a field for just this use case
+	savedDependencies := cf.Dependencies
+	if cf.APIVersion == chart.APIVersionV1 {
+		cf.Dependencies = nil
+	}
 	out, err := yaml.Marshal(cf)
+	if cf.APIVersion == chart.APIVersionV1 {
+		cf.Dependencies = savedDependencies
+	}
 	if err != nil {
 		return err
 	}
diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go
index c67cde04f..390f12f4c 100644
--- a/pkg/chartutil/create.go
+++ b/pkg/chartutil/create.go
@@ -103,6 +103,8 @@ fullnameOverride: ""
 serviceAccount:
   # Specifies whether a service account should be created
   create: true
+  # Annotations to add to the service account
+  annotations: {}
   # The name of the service account to use.
   # If not set and create is true, a name is generated using the fullname template
   name:
@@ -170,6 +172,7 @@ const defaultIgnore = `# Patterns to ignore when building packages.
 *.swp
 *.bak
 *.tmp
+*.orig
 *~
 # Various IDEs
 .project
@@ -302,6 +305,10 @@ metadata:
   name: {{ include "<CHARTNAME>.serviceAccountName" . }}
   labels:
 {{ include "<CHARTNAME>.labels" . | nindent 4 }}
+  {{- with .Values.serviceAccount.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
 {{- end -}}
 `
 
diff --git a/pkg/chartutil/doc.go b/pkg/chartutil/doc.go
index 5dd9c7038..efcda2cfa 100644
--- a/pkg/chartutil/doc.go
+++ b/pkg/chartutil/doc.go
@@ -17,7 +17,7 @@ limitations under the License.
 /*Package chartutil contains tools for working with charts.
 
 Charts are described in the protocol buffer definition (pkg/proto/charts).
-This packe provides utilities for serializing and deserializing charts.
+This package provides utilities for serializing and deserializing charts.
 
 A chart can be represented on the file system in one of two ways:
 
@@ -25,7 +25,7 @@ A chart can be represented on the file system in one of two ways:
 	- As a tarred gzipped file containing a directory that then contains a
 	Chart.yaml file.
 
-This package provides utilitites for working with those file formats.
+This package provides utilities for working with those file formats.
 
 The preferred way of loading a chart is using 'loader.Load`:
 
diff --git a/pkg/chartutil/jsonschema.go b/pkg/chartutil/jsonschema.go
index 0848faaf2..753dc98c1 100644
--- a/pkg/chartutil/jsonschema.go
+++ b/pkg/chartutil/jsonschema.go
@@ -39,10 +39,10 @@ func ValidateAgainstSchema(chrt *chart.Chart, values map[string]interface{}) err
 		}
 	}
 
-	// For each dependency, recurively call this function with the coalesced values
-	for _, subchrt := range chrt.Dependencies() {
-		subchrtValues := values[subchrt.Name()].(map[string]interface{})
-		if err := ValidateAgainstSchema(subchrt, subchrtValues); err != nil {
+	// For each dependency, recursively call this function with the coalesced values
+	for _, subchart := range chrt.Dependencies() {
+		subchartValues := values[subchart.Name()].(map[string]interface{})
+		if err := ValidateAgainstSchema(subchart, subchartValues); err != nil {
 			sb.WriteString(err.Error())
 		}
 	}
diff --git a/pkg/chartutil/save.go b/pkg/chartutil/save.go
index bc8f5bdd9..fb985bb59 100644
--- a/pkg/chartutil/save.go
+++ b/pkg/chartutil/save.go
@@ -23,6 +23,7 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
+	"time"
 
 	"github.com/pkg/errors"
 	"sigs.k8s.io/yaml"
@@ -141,8 +142,17 @@ func Save(c *chart.Chart, outDir string) (string, error) {
 func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
 	base := filepath.Join(prefix, c.Name())
 
+	// Pull out the dependencies of a v1 Chart, since there's no way
+	// to tell the serializer to skip a field for just this use case
+	savedDependencies := c.Metadata.Dependencies
+	if c.Metadata.APIVersion == chart.APIVersionV1 {
+		c.Metadata.Dependencies = nil
+	}
 	// Save Chart.yaml
 	cdata, err := yaml.Marshal(c.Metadata)
+	if c.Metadata.APIVersion == chart.APIVersionV1 {
+		c.Metadata.Dependencies = savedDependencies
+	}
 	if err != nil {
 		return err
 	}
@@ -198,9 +208,10 @@ func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
 func writeToTar(out *tar.Writer, name string, body []byte) error {
 	// TODO: Do we need to create dummy parent directory names if none exist?
 	h := &tar.Header{
-		Name: name,
-		Mode: 0644,
-		Size: int64(len(body)),
+		Name:    name,
+		Mode:    0644,
+		Size:    int64(len(body)),
+		ModTime: time.Now(),
 	}
 	if err := out.WriteHeader(h); err != nil {
 		return err
diff --git a/pkg/cli/environment.go b/pkg/cli/environment.go
index 28e7873be..5f947aec7 100644
--- a/pkg/cli/environment.go
+++ b/pkg/cli/environment.go
@@ -52,7 +52,7 @@ type EnvSettings struct {
 	RegistryConfig string
 	// RepositoryConfig is the path to the repositories file.
 	RepositoryConfig string
-	// Repositoryache is the path to the repository cache directory.
+	// RepositoryCache is the path to the repository cache directory.
 	RepositoryCache string
 	// PluginsDirectory is the path to the plugins directory.
 	PluginsDirectory string
diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go
index 81dd53614..e46af6944 100644
--- a/pkg/downloader/manager.go
+++ b/pkg/downloader/manager.go
@@ -163,7 +163,7 @@ func (m *Manager) Update() error {
 	}
 
 	// Finally, we need to write the lockfile.
-	return writeLock(m.ChartPath, lock)
+	return writeLock(m.ChartPath, lock, c.Metadata.APIVersion == chart.APIVersionV1)
 }
 
 func (m *Manager) loadChartDir() (*chart.Chart, error) {
@@ -634,12 +634,16 @@ func (m *Manager) loadChartRepositories() (map[string]*repo.ChartRepository, err
 }
 
 // writeLock writes a lockfile to disk
-func writeLock(chartpath string, lock *chart.Lock) error {
+func writeLock(chartpath string, lock *chart.Lock, legacyLockfile bool) error {
 	data, err := yaml.Marshal(lock)
 	if err != nil {
 		return err
 	}
-	dest := filepath.Join(chartpath, "Chart.lock")
+	lockfileName := "Chart.lock"
+	if legacyLockfile {
+		lockfileName = "requirements.lock"
+	}
+	dest := filepath.Join(chartpath, lockfileName)
 	return ioutil.WriteFile(dest, data, 0644)
 }
 
diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go
index 5a7d54993..1d98cd763 100644
--- a/pkg/engine/engine.go
+++ b/pkg/engine/engine.go
@@ -27,6 +27,7 @@ import (
 	"text/template"
 
 	"github.com/pkg/errors"
+	"k8s.io/client-go/rest"
 
 	"helm.sh/helm/v3/pkg/chart"
 	"helm.sh/helm/v3/pkg/chartutil"
@@ -39,6 +40,8 @@ type Engine struct {
 	Strict bool
 	// In LintMode, some 'required' template values may be missing, so don't fail
 	LintMode bool
+	// the rest config to connect to te kubernetes api
+	config *rest.Config
 }
 
 // Render takes a chart, optional values, and value overrides, and attempts to render the Go templates.
@@ -71,6 +74,15 @@ func Render(chrt *chart.Chart, values chartutil.Values) (map[string]string, erro
 	return new(Engine).Render(chrt, values)
 }
 
+// RenderWithClient takes a chart, optional values, and value overrides, and attempts to
+// render the Go templates using the default options. This engine is client aware and so can have template
+// functions that interact with the client
+func RenderWithClient(chrt *chart.Chart, values chartutil.Values, config *rest.Config) (map[string]string, error) {
+	return Engine{
+		config: config,
+	}.Render(chrt, values)
+}
+
 // renderable is an object that can be rendered.
 type renderable struct {
 	// tpl is the current template.
@@ -100,7 +112,7 @@ func (e Engine) initFunMap(t *template.Template, referenceTpls map[string]render
 		var buf strings.Builder
 		for _, n := range includedNames {
 			if n == name {
-				return "", errors.Wrapf(fmt.Errorf("unable to excute template"), "rendering template has a nested reference name: %s", name)
+				return "", errors.Wrapf(fmt.Errorf("unable to execute template"), "rendering template has a nested reference name: %s", name)
 			}
 		}
 		includedNames = append(includedNames, name)
@@ -157,6 +169,9 @@ func (e Engine) initFunMap(t *template.Template, referenceTpls map[string]render
 		}
 		return val, nil
 	}
+	if e.config != nil {
+		funcMap["lookup"] = NewLookupFunction(e.config)
+	}
 
 	t.Funcs(funcMap)
 }
diff --git a/pkg/engine/lookup_func.go b/pkg/engine/lookup_func.go
new file mode 100644
index 000000000..14f2351b4
--- /dev/null
+++ b/pkg/engine/lookup_func.go
@@ -0,0 +1,106 @@
+/*
+Copyright The Helm Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package engine
+
+import (
+	"log"
+	"strings"
+
+	"github.com/pkg/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/client-go/discovery"
+	"k8s.io/client-go/dynamic"
+	"k8s.io/client-go/rest"
+)
+
+type lookupFunc = func(apiversion string, resource string, namespace string, name string) (map[string]interface{}, error)
+
+func NewLookupFunction(config *rest.Config) lookupFunc {
+	return func(apiversion string, resource string, namespace string, name string) (map[string]interface{}, error) {
+		var client dynamic.ResourceInterface
+		c, namespaced, err := getDynamicClientOnKind(apiversion, resource, config)
+		if err != nil {
+			return map[string]interface{}{}, err
+		}
+		if namespaced && namespace != "" {
+			client = c.Namespace(namespace)
+		} else {
+			client = c
+		}
+		if name != "" {
+			//this will return a single object
+			obj, err := client.Get(name, metav1.GetOptions{})
+			if err != nil {
+				return map[string]interface{}{}, err
+			}
+			return obj.UnstructuredContent(), nil
+		}
+		//this will return a list
+		obj, err := client.List(metav1.ListOptions{})
+		if err != nil {
+			return map[string]interface{}{}, err
+		}
+		return obj.UnstructuredContent(), nil
+	}
+}
+
+// getDynamicClientOnUnstructured returns a dynamic client on an Unstructured type. This client can be further namespaced.
+func getDynamicClientOnKind(apiversion string, kind string, config *rest.Config) (dynamic.NamespaceableResourceInterface, bool, error) {
+	gvk := schema.FromAPIVersionAndKind(apiversion, kind)
+	apiRes, err := getAPIReourceForGVK(gvk, config)
+	if err != nil {
+		log.Printf("[ERROR] unable to get apiresource from unstructured: %s , error %s", gvk.String(), err)
+		return nil, false, errors.Wrapf(err, "unable to get apiresource from unstructured: %s", gvk.String())
+	}
+	gvr := schema.GroupVersionResource{
+		Group:    apiRes.Group,
+		Version:  apiRes.Version,
+		Resource: apiRes.Name,
+	}
+	intf, err := dynamic.NewForConfig(config)
+	if err != nil {
+		log.Printf("[ERROR] unable to get dynamic client %s", err)
+		return nil, false, err
+	}
+	res := intf.Resource(gvr)
+	return res, apiRes.Namespaced, nil
+}
+
+func getAPIReourceForGVK(gvk schema.GroupVersionKind, config *rest.Config) (metav1.APIResource, error) {
+	res := metav1.APIResource{}
+	discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
+	if err != nil {
+		log.Printf("[ERROR] unable to create discovery client %s", err)
+		return res, err
+	}
+	resList, err := discoveryClient.ServerResourcesForGroupVersion(gvk.GroupVersion().String())
+	if err != nil {
+		log.Printf("[ERROR] unable to retrieve resource list for: %s , error: %s", gvk.GroupVersion().String(), err)
+		return res, err
+	}
+	for _, resource := range resList.APIResources {
+		//if a resource contains a "/" it's referencing a subresource. we don't support suberesource for now.
+		if resource.Kind == gvk.Kind && !strings.Contains(resource.Name, "/") {
+			res = resource
+			res.Group = gvk.Group
+			res.Version = gvk.Version
+			break
+		}
+	}
+	return res, nil
+}
diff --git a/pkg/getter/httpgetter.go b/pkg/getter/httpgetter.go
index 89abfb1cf..5b476ff2d 100644
--- a/pkg/getter/httpgetter.go
+++ b/pkg/getter/httpgetter.go
@@ -27,7 +27,7 @@ import (
 	"helm.sh/helm/v3/internal/version"
 )
 
-// HTTPGetter is the efault HTTP(/S) backend handler
+// HTTPGetter is the default HTTP(/S) backend handler
 type HTTPGetter struct {
 	opts options
 }
diff --git a/pkg/helmpath/home.go b/pkg/helmpath/home.go
index 0b0f110a5..b3f14c558 100644
--- a/pkg/helmpath/home.go
+++ b/pkg/helmpath/home.go
@@ -25,10 +25,19 @@ func CachePath(elem ...string) string { return lp.cachePath(elem...) }
 // DataPath returns the path where Helm stores data.
 func DataPath(elem ...string) string { return lp.dataPath(elem...) }
 
-// CacheIndex returns the path to an index for the given named repository.
+// CacheIndexFile returns the path to an index for the given named repository.
 func CacheIndexFile(name string) string {
 	if name != "" {
 		name += "-"
 	}
 	return name + "index.yaml"
 }
+
+// CacheChartsFile returns the path to a text file listing all the charts
+// within the given named repository.
+func CacheChartsFile(name string) string {
+	if name != "" {
+		name += "-"
+	}
+	return name + "charts.txt"
+}
diff --git a/pkg/kube/client.go b/pkg/kube/client.go
index ab1f600ff..cdd996925 100644
--- a/pkg/kube/client.go
+++ b/pkg/kube/client.go
@@ -30,10 +30,12 @@ import (
 	"github.com/pkg/errors"
 	batch "k8s.io/api/batch/v1"
 	v1 "k8s.io/api/core/v1"
+	apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/fields"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/strategicpatch"
@@ -41,6 +43,7 @@ import (
 	"k8s.io/cli-runtime/pkg/genericclioptions"
 	"k8s.io/cli-runtime/pkg/resource"
 	"k8s.io/client-go/kubernetes/scheme"
+	cachetools "k8s.io/client-go/tools/cache"
 	watchtools "k8s.io/client-go/tools/watch"
 	cmdutil "k8s.io/kubectl/pkg/cmd/util"
 )
@@ -60,6 +63,10 @@ func New(getter genericclioptions.RESTClientGetter) *Client {
 		getter = genericclioptions.NewConfigFlags(true)
 	}
 	// Add CRDs to the scheme. They are missing by default.
+	if err := apiextv1.AddToScheme(scheme.Scheme); err != nil {
+		// This should never happen.
+		panic(err)
+	}
 	if err := apiextv1beta1.AddToScheme(scheme.Scheme); err != nil {
 		// This should never happen.
 		panic(err)
@@ -195,6 +202,11 @@ func (c *Client) Update(original, target ResourceList, force bool) (*Result, err
 	}
 
 	for _, info := range original.Difference(target) {
+		if info.Mapping.GroupVersionKind.Kind == "CustomResourceDefinition" {
+			c.Log("Skipping the deletion of CustomResourceDefinition %q", info.Name)
+			continue
+		}
+
 		c.Log("Deleting %q in %s...", info.Name, info.Namespace)
 		res.Deleted = append(res.Deleted, info)
 		if err := deleteResource(info); err != nil {
@@ -217,6 +229,11 @@ func (c *Client) Delete(resources ResourceList) (*Result, []error) {
 	var errs []error
 	res := &Result{}
 	err := perform(resources, func(info *resource.Info) error {
+		if info.Mapping.GroupVersionKind.Kind == "CustomResourceDefinition" {
+			c.Log("Skipping the deletion of CustomResourceDefinition %q", info.Name)
+			return nil
+		}
+
 		c.Log("Starting delete for %q %s", info.Name, info.Mapping.GroupVersionKind.Kind)
 		if err := c.skipIfNotFound(deleteResource(info)); err != nil {
 			// Collect the error and continue on
@@ -353,7 +370,12 @@ func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.P
 	// returned from ConvertToVersion. Anything that's unstructured should
 	// use the jsonpatch.CreateMergePatch. Strategic Merge Patch is not supported
 	// on objects like CRDs.
-	if _, ok := versionedObject.(runtime.Unstructured); ok {
+	_, isUnstructured := versionedObject.(runtime.Unstructured)
+
+	// On newer K8s versions, CRDs aren't unstructured but has this dedicated type
+	_, isCRD := versionedObject.(*apiextv1beta1.CustomResourceDefinition)
+
+	if isUnstructured || isCRD {
 		// fall back to generic JSON merge patch
 		patch, err := jsonpatch.CreateMergePatch(oldData, newData)
 		return patch, types.MergePatchType, err
@@ -419,10 +441,13 @@ func (c *Client) watchUntilReady(timeout time.Duration, info *resource.Info) err
 
 	c.Log("Watching for changes to %s %s with timeout of %v", kind, info.Name, timeout)
 
-	w, err := resource.NewHelper(info.Client, info.Mapping).WatchSingle(info.Namespace, info.Name, info.ResourceVersion)
+	// Use a selector on the name of the resource. This should be unique for the
+	// given version and kind
+	selector, err := fields.ParseSelector(fmt.Sprintf("metadata.name=%s", info.Name))
 	if err != nil {
 		return err
 	}
+	lw := cachetools.NewListWatchFromClient(info.Client, info.Mapping.Resource.Resource, info.Namespace, selector)
 
 	// What we watch for depends on the Kind.
 	// - For a Job, we watch for completion.
@@ -432,7 +457,7 @@ func (c *Client) watchUntilReady(timeout time.Duration, info *resource.Info) err
 
 	ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), timeout)
 	defer cancel()
-	_, err = watchtools.UntilWithoutRetry(ctx, w, func(e watch.Event) (bool, error) {
+	_, err = watchtools.ListWatchUntil(ctx, lw, func(e watch.Event) (bool, error) {
 		// Make sure the incoming object is versioned as we use unstructured
 		// objects when we build manifests
 		obj := convertWithMapper(e.Object, info.Mapping)
diff --git a/pkg/kube/fake/printer.go b/pkg/kube/fake/printer.go
index ec75aa790..58b389ab5 100644
--- a/pkg/kube/fake/printer.go
+++ b/pkg/kube/fake/printer.go
@@ -33,7 +33,7 @@ type PrintingKubeClient struct {
 	Out io.Writer
 }
 
-// isReachable checks if the cluster is reachable
+// IsReachable checks if the cluster is reachable
 func (p *PrintingKubeClient) IsReachable() error {
 	return nil
 }
diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go
index 70cb83bc5..91a64fe13 100644
--- a/pkg/lint/rules/chartfile.go
+++ b/pkg/lint/rules/chartfile.go
@@ -40,7 +40,7 @@ func Chartfile(linter *support.Linter) {
 	chartFile, err := chartutil.LoadChartfile(chartPath)
 	validChartFile := linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartYamlFormat(err))
 
-	// Guard clause. Following linter rules require a parseable ChartFile
+	// Guard clause. Following linter rules require a parsable ChartFile
 	if !validChartFile {
 		return
 	}
diff --git a/pkg/plugin/installer/vcs_installer.go b/pkg/plugin/installer/vcs_installer.go
index 21a65cd13..1a5d74cca 100644
--- a/pkg/plugin/installer/vcs_installer.go
+++ b/pkg/plugin/installer/vcs_installer.go
@@ -135,7 +135,7 @@ func (i *VCSInstaller) solveVersion(repo vcs.Repo) (string, error) {
 	sort.Sort(sort.Reverse(semver.Collection(semvers)))
 	for _, v := range semvers {
 		if constraint.Check(v) {
-			// If the constrint passes get the original reference
+			// If the constraint passes get the original reference
 			ver := v.Original()
 			debug("setting to %s", ver)
 			return ver, nil
diff --git a/pkg/release/status.go b/pkg/release/status.go
index cd025e279..49b0f1544 100644
--- a/pkg/release/status.go
+++ b/pkg/release/status.go
@@ -19,12 +19,13 @@ package release
 type Status string
 
 // Describe the status of a release
+// NOTE: Make sure to update cmd/helm/status.go when adding or modifying any of these statuses.
 const (
 	// StatusUnknown indicates that a release is in an uncertain state.
 	StatusUnknown Status = "unknown"
 	// StatusDeployed indicates that the release has been pushed to Kubernetes.
 	StatusDeployed Status = "deployed"
-	// StatusUninstalled indicates that a release has been uninstalled from Kubermetes.
+	// StatusUninstalled indicates that a release has been uninstalled from Kubernetes.
 	StatusUninstalled Status = "uninstalled"
 	// StatusSuperseded indicates that this release object is outdated and a newer one exists.
 	StatusSuperseded Status = "superseded"
diff --git a/pkg/releaseutil/kind_sorter.go b/pkg/releaseutil/kind_sorter.go
index a5110a100..92ffa03f2 100644
--- a/pkg/releaseutil/kind_sorter.go
+++ b/pkg/releaseutil/kind_sorter.go
@@ -31,12 +31,12 @@ var InstallOrder KindSortOrder = []string{
 	"LimitRange",
 	"PodSecurityPolicy",
 	"PodDisruptionBudget",
+	"ServiceAccount",
 	"Secret",
 	"ConfigMap",
 	"StorageClass",
 	"PersistentVolume",
 	"PersistentVolumeClaim",
-	"ServiceAccount",
 	"CustomResourceDefinition",
 	"ClusterRole",
 	"ClusterRoleList",
@@ -85,12 +85,12 @@ var UninstallOrder KindSortOrder = []string{
 	"ClusterRoleList",
 	"ClusterRole",
 	"CustomResourceDefinition",
-	"ServiceAccount",
 	"PersistentVolumeClaim",
 	"PersistentVolume",
 	"StorageClass",
 	"ConfigMap",
 	"Secret",
+	"ServiceAccount",
 	"PodDisruptionBudget",
 	"PodSecurityPolicy",
 	"LimitRange",
@@ -101,10 +101,10 @@ var UninstallOrder KindSortOrder = []string{
 
 // sortByKind does an in-place sort of manifests by Kind.
 //
-// Results are sorted by 'ordering'
+// Results are sorted by 'ordering', keeping order of items with equal kind/priority
 func sortByKind(manifests []Manifest, ordering KindSortOrder) []Manifest {
 	ks := newKindSorter(manifests, ordering)
-	sort.Sort(ks)
+	sort.Stable(ks)
 	return ks.manifests
 }
 
@@ -134,13 +134,13 @@ func (k *kindSorter) Less(i, j int) bool {
 	b := k.manifests[j]
 	first, aok := k.ordering[a.Head.Kind]
 	second, bok := k.ordering[b.Head.Kind]
-	// if same kind (including unknown) sub sort alphanumeric
-	if first == second {
-		// if both are unknown and of different kind sort by kind alphabetically
-		if !aok && !bok && a.Head.Kind != b.Head.Kind {
+
+	if !aok && !bok {
+		// if both are unknown then sort alphabetically by kind, keep original order if same kind
+		if a.Head.Kind != b.Head.Kind {
 			return a.Head.Kind < b.Head.Kind
 		}
-		return a.Name < b.Name
+		return first < second
 	}
 	// unknown kind is last
 	if !aok {
@@ -149,6 +149,6 @@ func (k *kindSorter) Less(i, j int) bool {
 	if !bok {
 		return true
 	}
-	// sort different kinds
+	// sort different kinds, keep original order if same priority
 	return first < second
 }
diff --git a/pkg/releaseutil/manifest.go b/pkg/releaseutil/manifest.go
index 37503b390..0b04a4599 100644
--- a/pkg/releaseutil/manifest.go
+++ b/pkg/releaseutil/manifest.go
@@ -19,6 +19,7 @@ package releaseutil
 import (
 	"fmt"
 	"regexp"
+	"strconv"
 	"strings"
 )
 
@@ -37,8 +38,9 @@ var sep = regexp.MustCompile("(?:^|\\s*\n)---\\s*")
 // SplitManifests takes a string of manifest and returns a map contains individual manifests
 func SplitManifests(bigFile string) map[string]string {
 	// Basically, we're quickly splitting a stream of YAML documents into an
-	// array of YAML docs. In the current implementation, the file name is just
-	// a place holder, and doesn't have any further meaning.
+	// array of YAML docs. The file name is just a place holder, but should be
+	// integer-sortable so that manifests get output in the same order as the
+	// input (see `BySplitManifestsOrder`).
 	tpl := "manifest-%d"
 	res := map[string]string{}
 	// Making sure that any extra whitespace in YAML stream doesn't interfere in splitting documents correctly.
@@ -56,3 +58,15 @@ func SplitManifests(bigFile string) map[string]string {
 	}
 	return res
 }
+
+// BySplitManifestsOrder sorts by in-file manifest order, as provided in function `SplitManifests`
+type BySplitManifestsOrder []string
+
+func (a BySplitManifestsOrder) Len() int { return len(a) }
+func (a BySplitManifestsOrder) Less(i, j int) bool {
+	// Split `manifest-%d`
+	anum, _ := strconv.ParseInt(a[i][len("manifest-"):], 10, 0)
+	bnum, _ := strconv.ParseInt(a[j][len("manifest-"):], 10, 0)
+	return anum < bnum
+}
+func (a BySplitManifestsOrder) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
diff --git a/pkg/releaseutil/manifest_sorter.go b/pkg/releaseutil/manifest_sorter.go
index 5f4b4e8d9..24b0c3c95 100644
--- a/pkg/releaseutil/manifest_sorter.go
+++ b/pkg/releaseutil/manifest_sorter.go
@@ -19,6 +19,7 @@ package releaseutil
 import (
 	"log"
 	"path"
+	"sort"
 	"strconv"
 	"strings"
 
@@ -74,10 +75,17 @@ var events = map[string]release.HookEvent{
 //
 // Files that do not parse into the expected format are simply placed into a map and
 // returned.
-func SortManifests(files map[string]string, apis chartutil.VersionSet, sort KindSortOrder) ([]*release.Hook, []Manifest, error) {
+func SortManifests(files map[string]string, apis chartutil.VersionSet, ordering KindSortOrder) ([]*release.Hook, []Manifest, error) {
 	result := &result{}
 
-	for filePath, c := range files {
+	var sortedFilePaths []string
+	for filePath := range files {
+		sortedFilePaths = append(sortedFilePaths, filePath)
+	}
+	sort.Strings(sortedFilePaths)
+
+	for _, filePath := range sortedFilePaths {
+		content := files[filePath]
 
 		// Skip partials. We could return these as a separate map, but there doesn't
 		// seem to be any need for that at this time.
@@ -85,12 +93,12 @@ func SortManifests(files map[string]string, apis chartutil.VersionSet, sort Kind
 			continue
 		}
 		// Skip empty files and log this.
-		if strings.TrimSpace(c) == "" {
+		if strings.TrimSpace(content) == "" {
 			continue
 		}
 
 		manifestFile := &manifestFile{
-			entries: SplitManifests(c),
+			entries: SplitManifests(content),
 			path:    filePath,
 			apis:    apis,
 		}
@@ -100,7 +108,7 @@ func SortManifests(files map[string]string, apis chartutil.VersionSet, sort Kind
 		}
 	}
 
-	return result.hooks, sortByKind(result.generic, sort), nil
+	return result.hooks, sortByKind(result.generic, ordering), nil
 }
 
 // sort takes a manifestFile object which may contain multiple resource definition
@@ -123,7 +131,16 @@ func SortManifests(files map[string]string, apis chartutil.VersionSet, sort Kind
 // 		annotations:
 // 			helm.sh/hook-delete-policy: hook-succeeded
 func (file *manifestFile) sort(result *result) error {
-	for _, m := range file.entries {
+	// Go through manifests in order found in file (function `SplitManifests` creates integer-sortable keys)
+	var sortedEntryKeys []string
+	for entryKey := range file.entries {
+		sortedEntryKeys = append(sortedEntryKeys, entryKey)
+	}
+	sort.Sort(BySplitManifestsOrder(sortedEntryKeys))
+
+	for _, entryKey := range sortedEntryKeys {
+		m := file.entries[entryKey]
+
 		var entry SimpleHead
 		if err := yaml.Unmarshal([]byte(m), &entry); err != nil {
 			return errors.Wrapf(err, "YAML parse error on %s", file.path)
diff --git a/pkg/repo/chartrepo.go b/pkg/repo/chartrepo.go
index c8d0d6a3d..38b6b8fb0 100644
--- a/pkg/repo/chartrepo.go
+++ b/pkg/repo/chartrepo.go
@@ -133,10 +133,21 @@ func (r *ChartRepository) DownloadIndexFile() (string, error) {
 		return "", err
 	}
 
-	if _, err := loadIndex(index); err != nil {
+	indexFile, err := loadIndex(index)
+	if err != nil {
 		return "", err
 	}
 
+	// Create the chart list file in the cache directory
+	var charts strings.Builder
+	for name := range indexFile.Entries {
+		fmt.Fprintln(&charts, name)
+	}
+	chartsFile := filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name))
+	os.MkdirAll(filepath.Dir(chartsFile), 0755)
+	ioutil.WriteFile(chartsFile, []byte(charts.String()), 0644)
+
+	// Create the index file in the cache directory
 	fname := filepath.Join(r.CachePath, helmpath.CacheIndexFile(r.Config.Name))
 	os.MkdirAll(filepath.Dir(fname), 0755)
 	return fname, ioutil.WriteFile(fname, index, 0644)
diff --git a/pkg/repo/doc.go b/pkg/repo/doc.go
index 19ccf267c..05650100b 100644
--- a/pkg/repo/doc.go
+++ b/pkg/repo/doc.go
@@ -27,7 +27,7 @@ The first is the 'index.yaml' format, which is expressed like this:
 	entries:
 	  frobnitz:
 	  - created: 2016-09-29T12:14:34.830161306-06:00
-		description: This is a frobniz.
+		description: This is a frobnitz.
 		digest: 587bd19a9bd9d2bc4a6d25ab91c8c8e7042c47b4ac246e37bf8e1e74386190f4
 		home: http://example.com
 		keywords:
diff --git a/pkg/repo/index.go b/pkg/repo/index.go
index a7fea673b..36386665e 100644
--- a/pkg/repo/index.go
+++ b/pkg/repo/index.go
@@ -17,8 +17,6 @@ limitations under the License.
 package repo
 
 import (
-	"encoding/json"
-	"fmt"
 	"io/ioutil"
 	"os"
 	"path"
@@ -290,48 +288,3 @@ func loadIndex(data []byte) (*IndexFile, error) {
 	}
 	return i, nil
 }
-
-// unversionedEntry represents a deprecated pre-Alpha.5 format.
-//
-// This will be removed prior to v2.0.0
-type unversionedEntry struct {
-	Checksum  string          `json:"checksum"`
-	URL       string          `json:"url"`
-	Chartfile *chart.Metadata `json:"chartfile"`
-}
-
-// loadUnversionedIndex loads a pre-Alpha.5 index.yaml file.
-//
-// This format is deprecated. This function will be removed prior to v2.0.0.
-func loadUnversionedIndex(data []byte) (*IndexFile, error) {
-	fmt.Fprintln(os.Stderr, "WARNING: Deprecated index file format. Try 'helm repo update'")
-	i := map[string]unversionedEntry{}
-
-	// This gets around an error in the YAML parser. Instead of parsing as YAML,
-	// we convert to JSON, and then decode again.
-	var err error
-	data, err = yaml.YAMLToJSON(data)
-	if err != nil {
-		return nil, err
-	}
-	if err := json.Unmarshal(data, &i); err != nil {
-		return nil, err
-	}
-
-	if len(i) == 0 {
-		return nil, ErrNoAPIVersion
-	}
-	ni := NewIndexFile()
-	for n, item := range i {
-		if item.Chartfile == nil || item.Chartfile.Name == "" {
-			parts := strings.Split(n, "-")
-			ver := ""
-			if len(parts) > 1 {
-				ver = strings.TrimSuffix(parts[1], ".tgz")
-			}
-			item.Chartfile = &chart.Metadata{Name: parts[0], Version: ver}
-		}
-		ni.Add(item.Chartfile, item.URL, "", item.Checksum)
-	}
-	return ni, nil
-}
diff --git a/pkg/storage/driver/secrets.go b/pkg/storage/driver/secrets.go
index eea285be1..dc55cf458 100644
--- a/pkg/storage/driver/secrets.go
+++ b/pkg/storage/driver/secrets.go
@@ -44,7 +44,7 @@ type Secrets struct {
 	Log  func(string, ...interface{})
 }
 
-// NewSecrets initializes a new Secrets wrapping an implmenetation of
+// NewSecrets initializes a new Secrets wrapping an implementation of
 // the kubernetes SecretsInterface.
 func NewSecrets(impl corev1.SecretInterface) *Secrets {
 	return &Secrets{
diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go
index 58a7eb06f..56881493b 100644
--- a/pkg/storage/storage.go
+++ b/pkg/storage/storage.go
@@ -66,7 +66,7 @@ func (s *Storage) Create(rls *rspb.Release) error {
 	return s.Driver.Create(makeKey(rls.Name, rls.Version), rls)
 }
 
-// Update update the release in storage. An error is returned if the
+// Update updates the release in storage. An error is returned if the
 // storage backend fails to update the release or if the release
 // does not exist.
 func (s *Storage) Update(rls *rspb.Release) error {
@@ -112,9 +112,6 @@ func (s *Storage) ListDeployed() ([]*rspb.Release, error) {
 func (s *Storage) Deployed(name string) (*rspb.Release, error) {
 	ls, err := s.DeployedAll(name)
 	if err != nil {
-		if strings.Contains(err.Error(), "not found") {
-			return nil, errors.Errorf("%q has no deployed releases", name)
-		}
 		return nil, err
 	}
 
@@ -122,7 +119,7 @@ func (s *Storage) Deployed(name string) (*rspb.Release, error) {
 		return nil, errors.Errorf("%q has no deployed releases", name)
 	}
 
-	return ls[0], err
+	return ls[0], nil
 }
 
 // DeployedAll returns all deployed releases with the provided name, or


Test patch:
diff --git a/cmd/helm/dependency_update_test.go b/cmd/helm/dependency_update_test.go
index 53d67ef59..1f9d55867 100644
--- a/cmd/helm/dependency_update_test.go
+++ b/cmd/helm/dependency_update_test.go
@@ -111,9 +111,9 @@ func TestDependencyUpdateCmd(t *testing.T) {
 	if _, err := os.Stat(expect); err != nil {
 		t.Fatalf("Expected %q: %s", expect, err)
 	}
-	dontExpect := dir(chartname, "charts/compressedchart-0.1.0.tgz")
-	if _, err := os.Stat(dontExpect); err == nil {
-		t.Fatalf("Unexpected %q", dontExpect)
+	unexpected := dir(chartname, "charts/compressedchart-0.1.0.tgz")
+	if _, err := os.Stat(unexpected); err == nil {
+		t.Fatalf("Unexpected %q", unexpected)
 	}
 }
 
@@ -182,7 +182,7 @@ func TestDependencyUpdateCmd_DontDeleteOldChartsOnError(t *testing.T) {
 func createTestingMetadata(name, baseURL string) *chart.Chart {
 	return &chart.Chart{
 		Metadata: &chart.Metadata{
-			APIVersion: chart.APIVersionV1,
+			APIVersion: chart.APIVersionV2,
 			Name:       name,
 			Version:    "1.2.3",
 			Dependencies: []*chart.Dependency{
diff --git a/cmd/helm/helm_test.go b/cmd/helm/helm_test.go
index 924e8e9d3..b7156daf3 100644
--- a/cmd/helm/helm_test.go
+++ b/cmd/helm/helm_test.go
@@ -31,6 +31,7 @@ import (
 	"helm.sh/helm/v3/internal/test"
 	"helm.sh/helm/v3/pkg/action"
 	"helm.sh/helm/v3/pkg/chartutil"
+	"helm.sh/helm/v3/pkg/cli"
 	kubefake "helm.sh/helm/v3/pkg/kube/fake"
 	"helm.sh/helm/v3/pkg/release"
 	"helm.sh/helm/v3/pkg/storage"
@@ -47,24 +48,26 @@ func init() {
 func runTestCmd(t *testing.T, tests []cmdTestCase) {
 	t.Helper()
 	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			defer resetEnv()()
-
-			storage := storageFixture()
-			for _, rel := range tt.rels {
-				if err := storage.Create(rel); err != nil {
-					t.Fatal(err)
+		for i := 0; i <= tt.repeat; i++ {
+			t.Run(tt.name, func(t *testing.T) {
+				defer resetEnv()()
+
+				storage := storageFixture()
+				for _, rel := range tt.rels {
+					if err := storage.Create(rel); err != nil {
+						t.Fatal(err)
+					}
 				}
-			}
-			t.Log("running cmd: ", tt.cmd)
-			_, out, err := executeActionCommandC(storage, tt.cmd)
-			if (err != nil) != tt.wantError {
-				t.Errorf("expected error, got '%v'", err)
-			}
-			if tt.golden != "" {
-				test.AssertGoldenString(t, out, tt.golden)
-			}
-		})
+				t.Logf("running cmd (attempt %d): %s", i+1, tt.cmd)
+				_, out, err := executeActionCommandC(storage, tt.cmd)
+				if (err != nil) != tt.wantError {
+					t.Errorf("expected error, got '%v'", err)
+				}
+				if tt.golden != "" {
+					test.AssertGoldenString(t, out, tt.golden)
+				}
+			})
+		}
 	}
 }
 
@@ -124,6 +127,9 @@ type cmdTestCase struct {
 	wantError bool
 	// Rels are the available releases at the start of the test.
 	rels []*release.Release
+	// Number of repeats (in case a feature was previously flaky and the test checks
+	// it's now stably producing identical results). 0 means test is run exactly once.
+	repeat int
 }
 
 func executeActionCommand(cmd string) (*cobra.Command, string, error) {
@@ -131,14 +137,14 @@ func executeActionCommand(cmd string) (*cobra.Command, string, error) {
 }
 
 func resetEnv() func() {
-	origSettings, origEnv := settings, os.Environ()
+	origEnv := os.Environ()
 	return func() {
 		os.Clearenv()
-		settings = origSettings
 		for _, pair := range origEnv {
 			kv := strings.SplitN(pair, "=", 2)
 			os.Setenv(kv[0], kv[1])
 		}
+		settings = cli.New()
 	}
 }
 
diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go
index 9ab25417b..e8b573dfc 100644
--- a/cmd/helm/install_test.go
+++ b/cmd/helm/install_test.go
@@ -183,6 +183,12 @@ func TestInstall(t *testing.T) {
 			wantError: true,
 			golden:    "output/subchart-schema-cli-negative.txt",
 		},
+		// Install deprecated chart
+		{
+			name:   "install with warning about deprecated chart",
+			cmd:    "install aeneas testdata/testcharts/deprecated --namespace default",
+			golden: "output/deprecated-chart.txt",
+		},
 	}
 
 	runTestActionCmd(t, tests)
diff --git a/cmd/helm/pull_test.go b/cmd/helm/pull_test.go
index 248195774..1aca66100 100644
--- a/cmd/helm/pull_test.go
+++ b/cmd/helm/pull_test.go
@@ -41,7 +41,10 @@ func TestPullCmd(t *testing.T) {
 	tests := []struct {
 		name         string
 		args         string
+		existFile    string
+		existDir     string
 		wantError    bool
+		wantErrorMsg string
 		failExpect   string
 		expectFile   string
 		expectDir    bool
@@ -87,10 +90,24 @@ func TestPullCmd(t *testing.T) {
 			expectFile: "./signtest",
 			expectDir:  true,
 		},
+		{
+			name:         "Fetch untar when file with same name existed",
+			args:         "test/test1 --untar --untardir test1",
+			existFile:    "test1",
+			wantError:    true,
+			wantErrorMsg: fmt.Sprintf("failed to untar: a file or directory with the name %s already exists", filepath.Join(srv.Root(), "test1")),
+		},
+		{
+			name:         "Fetch untar when dir with same name existed",
+			args:         "test/test2 --untar --untardir test2",
+			existDir:     "test2",
+			wantError:    true,
+			wantErrorMsg: fmt.Sprintf("failed to untar: a file or directory with the name %s already exists", filepath.Join(srv.Root(), "test2")),
+		},
 		{
 			name:         "Fetch, verify, untar",
-			args:         "test/signtest --verify --keyring=testdata/helm-test-key.pub --untar --untardir signtest",
-			expectFile:   "./signtest",
+			args:         "test/signtest --verify --keyring=testdata/helm-test-key.pub --untar --untardir signtest2",
+			expectFile:   "./signtest2",
 			expectDir:    true,
 			expectVerify: true,
 		},
@@ -127,9 +144,27 @@ func TestPullCmd(t *testing.T) {
 				filepath.Join(outdir, "repositories.yaml"),
 				outdir,
 			)
+			// Create file or Dir before helm pull --untar, see: https://github.com/helm/helm/issues/7182
+			if tt.existFile != "" {
+				file := filepath.Join(outdir, tt.existFile)
+				_, err := os.Create(file)
+				if err != nil {
+					t.Fatal("err")
+				}
+			}
+			if tt.existDir != "" {
+				file := filepath.Join(outdir, tt.existDir)
+				err := os.Mkdir(file, 0755)
+				if err != nil {
+					t.Fatal(err)
+				}
+			}
 			_, out, err := executeActionCommand(cmd)
 			if err != nil {
 				if tt.wantError {
+					if tt.wantErrorMsg != "" && tt.wantErrorMsg == err.Error() {
+						t.Fatalf("Actual error %s, not equal to expected error %s", err, tt.wantErrorMsg)
+					}
 					return
 				}
 				t.Fatalf("%q reported error: %s", tt.name, err)
diff --git a/cmd/helm/repo_add_test.go b/cmd/helm/repo_add_test.go
index 1ac61fba8..d1b9bc0fc 100644
--- a/cmd/helm/repo_add_test.go
+++ b/cmd/helm/repo_add_test.go
@@ -19,13 +19,16 @@ package main
 import (
 	"fmt"
 	"io/ioutil"
+	"os"
 	"path/filepath"
 	"sync"
 	"testing"
 
-	"gopkg.in/yaml.v2"
+	"sigs.k8s.io/yaml"
 
 	"helm.sh/helm/v3/internal/test/ensure"
+	"helm.sh/helm/v3/pkg/helmpath"
+	"helm.sh/helm/v3/pkg/helmpath/xdg"
 	"helm.sh/helm/v3/pkg/repo"
 	"helm.sh/helm/v3/pkg/repo/repotest"
 )
@@ -55,7 +58,8 @@ func TestRepoAdd(t *testing.T) {
 	}
 	defer ts.Stop()
 
-	repoFile := filepath.Join(ensure.TempDir(t), "repositories.yaml")
+	rootDir := ensure.TempDir(t)
+	repoFile := filepath.Join(rootDir, "repositories.yaml")
 
 	const testRepoName = "test-name"
 
@@ -65,6 +69,7 @@ func TestRepoAdd(t *testing.T) {
 		noUpdate: true,
 		repoFile: repoFile,
 	}
+	os.Setenv(xdg.CacheHomeEnvVar, rootDir)
 
 	if err := o.run(ioutil.Discard); err != nil {
 		t.Error(err)
@@ -79,6 +84,15 @@ func TestRepoAdd(t *testing.T) {
 		t.Errorf("%s was not successfully inserted into %s", testRepoName, repoFile)
 	}
 
+	idx := filepath.Join(helmpath.CachePath("repository"), helmpath.CacheIndexFile(testRepoName))
+	if _, err := os.Stat(idx); os.IsNotExist(err) {
+		t.Errorf("Error cache index file was not created for repository %s", testRepoName)
+	}
+	idx = filepath.Join(helmpath.CachePath("repository"), helmpath.CacheChartsFile(testRepoName))
+	if _, err := os.Stat(idx); os.IsNotExist(err) {
+		t.Errorf("Error cache charts file was not created for repository %s", testRepoName)
+	}
+
 	o.noUpdate = false
 
 	if err := o.run(ioutil.Discard); err != nil {
diff --git a/cmd/helm/repo_remove_test.go b/cmd/helm/repo_remove_test.go
index 3fdcbe9c3..85c76bb92 100644
--- a/cmd/helm/repo_remove_test.go
+++ b/cmd/helm/repo_remove_test.go
@@ -63,10 +63,13 @@ func TestRepoRemove(t *testing.T) {
 	}
 
 	idx := filepath.Join(rootDir, helmpath.CacheIndexFile(testRepoName))
-
 	mf, _ := os.Create(idx)
 	mf.Close()
 
+	idx2 := filepath.Join(rootDir, helmpath.CacheChartsFile(testRepoName))
+	mf, _ = os.Create(idx2)
+	mf.Close()
+
 	b.Reset()
 
 	if err := rmOpts.run(b); err != nil {
@@ -77,7 +80,11 @@ func TestRepoRemove(t *testing.T) {
 	}
 
 	if _, err := os.Stat(idx); err == nil {
-		t.Errorf("Error cache file was not removed for repository %s", testRepoName)
+		t.Errorf("Error cache index file was not removed for repository %s", testRepoName)
+	}
+
+	if _, err := os.Stat(idx2); err == nil {
+		t.Errorf("Error cache chart file was not removed for repository %s", testRepoName)
 	}
 
 	f, err := repo.LoadFile(repoFile)
diff --git a/cmd/helm/root_test.go b/cmd/helm/root_test.go
index 7d606b8a9..f3eef8b6d 100644
--- a/cmd/helm/root_test.go
+++ b/cmd/helm/root_test.go
@@ -31,7 +31,7 @@ func TestRootCmd(t *testing.T) {
 
 	tests := []struct {
 		name, args, cachePath, configPath, dataPath string
-		envars                                      map[string]string
+		envvars                                     map[string]string
 	}{
 		{
 			name: "defaults",
@@ -40,19 +40,19 @@ func TestRootCmd(t *testing.T) {
 		{
 			name:      "with $XDG_CACHE_HOME set",
 			args:      "home",
-			envars:    map[string]string{xdg.CacheHomeEnvVar: "/bar"},
+			envvars:   map[string]string{xdg.CacheHomeEnvVar: "/bar"},
 			cachePath: "/bar/helm",
 		},
 		{
 			name:       "with $XDG_CONFIG_HOME set",
 			args:       "home",
-			envars:     map[string]string{xdg.ConfigHomeEnvVar: "/bar"},
+			envvars:    map[string]string{xdg.ConfigHomeEnvVar: "/bar"},
 			configPath: "/bar/helm",
 		},
 		{
 			name:     "with $XDG_DATA_HOME set",
 			args:     "home",
-			envars:   map[string]string{xdg.DataHomeEnvVar: "/bar"},
+			envvars:  map[string]string{xdg.DataHomeEnvVar: "/bar"},
 			dataPath: "/bar/helm",
 		},
 	}
@@ -61,7 +61,7 @@ func TestRootCmd(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			defer ensure.HelmHome(t)()
 
-			for k, v := range tt.envars {
+			for k, v := range tt.envvars {
 				os.Setenv(k, v)
 			}
 
diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go
index 735829432..35a8e996b 100644
--- a/cmd/helm/template_test.go
+++ b/cmd/helm/template_test.go
@@ -84,6 +84,14 @@ func TestTemplateCmd(t *testing.T) {
 			cmd:    fmt.Sprintf("template '%s' --include-crds", chartPath),
 			golden: "output/template-with-crds.txt",
 		},
+		{
+			name:   "sorted output of manifests (order of filenames, then order of objects within each YAML file)",
+			cmd:    fmt.Sprintf("template '%s'", "testdata/testcharts/object-order"),
+			golden: "output/object-order.txt",
+			// Helm previously used random file order. Repeat the test so we
+			// don't accidentally get the expected result.
+			repeat: 10,
+		},
 	}
 	runTestCmd(t, tests)
 }
diff --git a/cmd/helm/testdata/output/deprecated-chart.txt b/cmd/helm/testdata/output/deprecated-chart.txt
new file mode 100644
index 000000000..e5be2c3f1
--- /dev/null
+++ b/cmd/helm/testdata/output/deprecated-chart.txt
@@ -0,0 +1,7 @@
+WARNING: This chart is deprecated
+NAME: aeneas
+LAST DEPLOYED: Fri Sep  2 22:04:05 1977
+NAMESPACE: default
+STATUS: deployed
+REVISION: 1
+TEST SUITE: None
diff --git a/cmd/helm/testdata/output/object-order.txt b/cmd/helm/testdata/output/object-order.txt
new file mode 100644
index 000000000..307f928f2
--- /dev/null
+++ b/cmd/helm/testdata/output/object-order.txt
@@ -0,0 +1,191 @@
+---
+# Source: object-order/templates/01-a.yml
+# 1
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: first
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+---
+# Source: object-order/templates/01-a.yml
+# 2
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: second
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+---
+# Source: object-order/templates/01-a.yml
+# 3
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: third
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+---
+# Source: object-order/templates/02-b.yml
+# 5
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: fifth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+---
+# Source: object-order/templates/02-b.yml
+# 7
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: seventh
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+---
+# Source: object-order/templates/02-b.yml
+# 8
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: eighth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+---
+# Source: object-order/templates/02-b.yml
+# 9
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: ninth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+---
+# Source: object-order/templates/02-b.yml
+# 10
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: tenth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+---
+# Source: object-order/templates/02-b.yml
+# 11
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: eleventh
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+---
+# Source: object-order/templates/02-b.yml
+# 12
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: twelfth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+---
+# Source: object-order/templates/02-b.yml
+# 13
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: thirteenth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+---
+# Source: object-order/templates/02-b.yml
+# 14
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: fourteenth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+---
+# Source: object-order/templates/02-b.yml
+# 15 (11th object within 02-b.yml, in order to test `SplitManifests` which assigns `manifest-10`
+# to this object which should then come *after* `manifest-9`)
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: fifteenth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+---
+# Source: object-order/templates/01-a.yml
+# 4 (Deployment should come after all NetworkPolicy manifests, since 'helm template' outputs in install order)
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: fourth
+spec:
+  selector:
+    matchLabels:
+      pod: fourth
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        pod: fourth
+    spec:
+      containers:
+        - name: hello-world
+          image: gcr.io/google-samples/node-hello:1.0
+---
+# Source: object-order/templates/02-b.yml
+# 6 (implementation detail: currently, 'helm template' outputs hook manifests last; and yes, NetworkPolicy won't make a reasonable hook, this is just a dummy unit test manifest)
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  annotations:
+    "helm.sh/hook": pre-install
+  name: sixth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
diff --git a/cmd/helm/testdata/output/search-single.txt b/cmd/helm/testdata/output/search-single.txt
deleted file mode 100644
index 936605ae1..000000000
--- a/cmd/helm/testdata/output/search-single.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-NAME           	CHART VERSION	APP VERSION	DESCRIPTION      
-testing/mariadb	0.3.0        	           	Chart for MariaDB
diff --git a/cmd/helm/testdata/output/status-with-resource.txt b/cmd/helm/testdata/output/status-with-resource.txt
deleted file mode 100644
index 5f6f4e663..000000000
--- a/cmd/helm/testdata/output/status-with-resource.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-NAME: flummoxed-chickadee
-LAST DEPLOYED: 2016-01-16 00:00:00 +0000 UTC
-NAMESPACE: default
-STATUS: deployed
-
-RESOURCES:
-resource A
-resource B
-
diff --git a/cmd/helm/testdata/output/status.yaml b/cmd/helm/testdata/output/status.yaml
deleted file mode 100644
index a7bc12276..000000000
--- a/cmd/helm/testdata/output/status.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-info:
-  deleted: "0001-01-01T00:00:00Z"
-  first_deployed: "0001-01-01T00:00:00Z"
-  last_deployed: "2016-01-16T00:00:00Z"
-  resources: |
-    resource A
-    resource B
-  status: deployed
-name: flummoxed-chickadee
-namespace: default
diff --git a/cmd/helm/testdata/output/version-client-shorthand.txt b/cmd/helm/testdata/output/version-client-shorthand.txt
index 0d9b536e6..4b493d31c 100644
--- a/cmd/helm/testdata/output/version-client-shorthand.txt
+++ b/cmd/helm/testdata/output/version-client-shorthand.txt
@@ -1,1 +1,1 @@
-version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""}
+version.BuildInfo{Version:"v3.0", GitCommit:"", GitTreeState:"", GoVersion:""}
diff --git a/cmd/helm/testdata/output/version-client.txt b/cmd/helm/testdata/output/version-client.txt
index 0d9b536e6..4b493d31c 100644
--- a/cmd/helm/testdata/output/version-client.txt
+++ b/cmd/helm/testdata/output/version-client.txt
@@ -1,1 +1,1 @@
-version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""}
+version.BuildInfo{Version:"v3.0", GitCommit:"", GitTreeState:"", GoVersion:""}
diff --git a/cmd/helm/testdata/output/version-short.txt b/cmd/helm/testdata/output/version-short.txt
index 5e7749489..d9fb9c736 100644
--- a/cmd/helm/testdata/output/version-short.txt
+++ b/cmd/helm/testdata/output/version-short.txt
@@ -1,1 +1,1 @@
-v3.0+unreleased
+v3.0
diff --git a/cmd/helm/testdata/output/version-template.txt b/cmd/helm/testdata/output/version-template.txt
index c12e29c2d..776c1919b 100644
--- a/cmd/helm/testdata/output/version-template.txt
+++ b/cmd/helm/testdata/output/version-template.txt
@@ -1,1 +1,1 @@
-Version: v3.0+unreleased
\ No newline at end of file
+Version: v3.0
\ No newline at end of file
diff --git a/cmd/helm/testdata/output/version.txt b/cmd/helm/testdata/output/version.txt
index 0d9b536e6..4b493d31c 100644
--- a/cmd/helm/testdata/output/version.txt
+++ b/cmd/helm/testdata/output/version.txt
@@ -1,1 +1,1 @@
-version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""}
+version.BuildInfo{Version:"v3.0", GitCommit:"", GitTreeState:"", GoVersion:""}
diff --git a/cmd/helm/testdata/testcharts/deprecated/Chart.yaml b/cmd/helm/testdata/testcharts/deprecated/Chart.yaml
new file mode 100644
index 000000000..10185beeb
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/deprecated/Chart.yaml
@@ -0,0 +1,8 @@
+apiVersion: v1
+description: Deprecated testing chart
+home: https://helm.sh/helm
+name: deprecated
+sources:
+  - https://github.com/helm/helm
+version: 0.1.0
+deprecated: true
diff --git a/cmd/helm/testdata/testcharts/deprecated/README.md b/cmd/helm/testdata/testcharts/deprecated/README.md
new file mode 100644
index 000000000..0df9a8bbc
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/deprecated/README.md
@@ -0,0 +1,3 @@
+#Deprecated
+
+This space intentionally left blank.
diff --git a/cmd/helm/testdata/testcharts/object-order/Chart.yaml b/cmd/helm/testdata/testcharts/object-order/Chart.yaml
new file mode 100644
index 000000000..d2eb42fd7
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/object-order/Chart.yaml
@@ -0,0 +1,5 @@
+apiVersion: v2
+name: object-order
+description: Test ordering of manifests in output
+type: application
+version: 0.1.0
diff --git a/cmd/helm/testdata/testcharts/object-order/templates/01-a.yml b/cmd/helm/testdata/testcharts/object-order/templates/01-a.yml
new file mode 100644
index 000000000..32aa4a475
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/object-order/templates/01-a.yml
@@ -0,0 +1,57 @@
+# 1
+kind: NetworkPolicy
+apiVersion: networking.k8s.io/v1
+metadata:
+  name: first
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+
+---
+
+# 2
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: second
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+
+---
+
+# 3
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: third
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+
+---
+
+# 4 (Deployment should come after all NetworkPolicy manifests, since 'helm template' outputs in install order)
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: fourth
+spec:
+  selector:
+    matchLabels:
+      pod: fourth
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        pod: fourth
+    spec:
+      containers:
+        - name: hello-world
+          image: gcr.io/google-samples/node-hello:1.0
diff --git a/cmd/helm/testdata/testcharts/object-order/templates/02-b.yml b/cmd/helm/testdata/testcharts/object-order/templates/02-b.yml
new file mode 100644
index 000000000..895db8cf7
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/object-order/templates/02-b.yml
@@ -0,0 +1,143 @@
+# 5
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: fifth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+
+---
+
+# 6 (implementation detail: currently, 'helm template' outputs hook manifests last; and yes, NetworkPolicy won't make a reasonable hook, this is just a dummy unit test manifest)
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  annotations:
+    "helm.sh/hook": pre-install
+  name: sixth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+
+---
+
+# 7
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: seventh
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+
+---
+
+# 8
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: eighth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+
+---
+
+# 9
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: ninth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+
+---
+
+# 10
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: tenth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+
+---
+
+# 11
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: eleventh
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+
+---
+
+# 12
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: twelfth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+
+---
+
+# 13
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: thirteenth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+
+---
+
+# 14
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: fourteenth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
+
+---
+
+# 15 (11th object within 02-b.yml, in order to test `SplitManifests` which assigns `manifest-10`
+# to this object which should then come *after* `manifest-9`)
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: fifteenth
+spec:
+  podSelector: {}
+  policyTypes:
+    - Egress
+    - Ingress
diff --git a/internal/third_party/dep/fs/fs_test.go b/internal/third_party/dep/fs/fs_test.go
index bf4b803f8..a9678d8c1 100644
--- a/internal/third_party/dep/fs/fs_test.go
+++ b/internal/third_party/dep/fs/fs_test.go
@@ -170,7 +170,7 @@ func TestCopyDir(t *testing.T) {
 func TestCopyDirFail_SrcInaccessible(t *testing.T) {
 	if runtime.GOOS == "windows" {
 		// XXX: setting permissions works differently in
-		// Microsoft Windows. Skipping this this until a
+		// Microsoft Windows. Skipping this until a
 		// compatible implementation is provided.
 		t.Skip("skipping on windows")
 	}
@@ -209,7 +209,7 @@ func TestCopyDirFail_SrcInaccessible(t *testing.T) {
 func TestCopyDirFail_DstInaccessible(t *testing.T) {
 	if runtime.GOOS == "windows" {
 		// XXX: setting permissions works differently in
-		// Microsoft Windows. Skipping this this until a
+		// Microsoft Windows. Skipping this until a
 		// compatible implementation is provided.
 		t.Skip("skipping on windows")
 	}
@@ -309,7 +309,7 @@ func TestCopyDirFailOpen(t *testing.T) {
 		// Microsoft Windows. os.Chmod(..., 0222) below is not
 		// enough for the file to be readonly, and os.Chmod(...,
 		// 0000) returns an invalid argument error. Skipping
-		// this this until a compatible implementation is
+		// this until a compatible implementation is
 		// provided.
 		t.Skip("skipping on windows")
 	}
@@ -478,7 +478,7 @@ func TestCopyFileSymlink(t *testing.T) {
 func TestCopyFileFail(t *testing.T) {
 	if runtime.GOOS == "windows" {
 		// XXX: setting permissions works differently in
-		// Microsoft Windows. Skipping this this until a
+		// Microsoft Windows. Skipping this until a
 		// compatible implementation is provided.
 		t.Skip("skipping on windows")
 	}
@@ -521,7 +521,7 @@ func TestCopyFileFail(t *testing.T) {
 }
 
 // setupInaccessibleDir creates a temporary location with a single
-// directory in it, in such a way that that directory is not accessible
+// directory in it, in such a way that directory is not accessible
 // after this function returns.
 //
 // op is called with the directory as argument, so that it can create
diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go
index 4637a4b10..d6f1c88cd 100644
--- a/pkg/action/install_test.go
+++ b/pkg/action/install_test.go
@@ -505,6 +505,14 @@ func TestNameAndChart(t *testing.T) {
 		t.Fatal("expected an error")
 	}
 	is.Equal("must either provide a name or specify --generate-name", err.Error())
+
+	instAction.NameTemplate = ""
+	instAction.ReleaseName = ""
+	_, _, err = instAction.NameAndChart([]string{"foo", chartName, "bar"})
+	if err == nil {
+		t.Fatal("expected an error")
+	}
+	is.Equal("expected at most two arguments, unexpected arguments: bar", err.Error())
 }
 
 func TestNameAndChartGenerateName(t *testing.T) {
diff --git a/pkg/action/list_test.go b/pkg/action/list_test.go
index cd86aee68..378a747b0 100644
--- a/pkg/action/list_test.go
+++ b/pkg/action/list_test.go
@@ -237,27 +237,36 @@ func makeMeSomeReleases(store *storage.Storage, t *testing.T) {
 }
 
 func TestFilterList(t *testing.T) {
-	one := releaseStub()
-	one.Name = "one"
-	one.Namespace = "default"
-	one.Version = 1
-	two := releaseStub()
-	two.Name = "two"
-	two.Namespace = "default"
-	two.Version = 1
-	anotherOldOne := releaseStub()
-	anotherOldOne.Name = "one"
-	anotherOldOne.Namespace = "testing"
-	anotherOldOne.Version = 1
-	anotherOne := releaseStub()
-	anotherOne.Name = "one"
-	anotherOne.Namespace = "testing"
-	anotherOne.Version = 2
-
-	list := []*release.Release{one, two, anotherOne}
-	expectedFilteredList := []*release.Release{one, two, anotherOne}
-
-	filteredList := filterList(list)
-
-	assert.ElementsMatch(t, expectedFilteredList, filteredList)
+	t.Run("should filter old versions of the same release", func(t *testing.T) {
+		r1 := releaseStub()
+		r1.Name = "r"
+		r1.Version = 1
+		r2 := releaseStub()
+		r2.Name = "r"
+		r2.Version = 2
+		another := releaseStub()
+		another.Name = "another"
+		another.Version = 1
+
+		filteredList := filterList([]*release.Release{r1, r2, another})
+		expectedFilteredList := []*release.Release{r2, another}
+
+		assert.ElementsMatch(t, expectedFilteredList, filteredList)
+	})
+
+	t.Run("should not filter out any version across namespaces", func(t *testing.T) {
+		r1 := releaseStub()
+		r1.Name = "r"
+		r1.Namespace = "default"
+		r1.Version = 1
+		r2 := releaseStub()
+		r2.Name = "r"
+		r2.Namespace = "testing"
+		r2.Version = 2
+
+		filteredList := filterList([]*release.Release{r1, r2})
+		expectedFilteredList := []*release.Release{r1, r2}
+
+		assert.ElementsMatch(t, expectedFilteredList, filteredList)
+	})
 }
diff --git a/pkg/chart/loader/load_test.go b/pkg/chart/loader/load_test.go
index 6576002eb..26513d359 100644
--- a/pkg/chart/loader/load_test.go
+++ b/pkg/chart/loader/load_test.go
@@ -461,7 +461,7 @@ func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) {
 				t.Fatalf("Expected 2 Dependency, got %d", len(dep.Dependencies()))
 			}
 		default:
-			t.Errorf("Unexpected dependeny %s", dep.Name())
+			t.Errorf("Unexpected dependency %s", dep.Name())
 		}
 	}
 }
diff --git a/pkg/chartutil/errors_test.go b/pkg/chartutil/errors_test.go
index 3f9d04a71..3f63e3733 100644
--- a/pkg/chartutil/errors_test.go
+++ b/pkg/chartutil/errors_test.go
@@ -20,7 +20,7 @@ import (
 	"testing"
 )
 
-func TestErrorNoTableDoesntPanic(t *testing.T) {
+func TestErrorNoTableDoesNotPanic(t *testing.T) {
 	x := "empty"
 
 	y := ErrNoTable{x}
@@ -28,7 +28,7 @@ func TestErrorNoTableDoesntPanic(t *testing.T) {
 	t.Logf("error is: %s", y)
 }
 
-func TestErrorNoValueDoesntPanic(t *testing.T) {
+func TestErrorNoValueDoesNotPanic(t *testing.T) {
 	x := "empty"
 
 	y := ErrNoValue{x}
diff --git a/pkg/chartutil/jsonschema_test.go b/pkg/chartutil/jsonschema_test.go
index 2677ee0ea..33f009259 100644
--- a/pkg/chartutil/jsonschema_test.go
+++ b/pkg/chartutil/jsonschema_test.go
@@ -63,7 +63,7 @@ func TestValidateAgainstSingleSchemaNegative(t *testing.T) {
 	}
 }
 
-const subchrtSchema = `{
+const subchartSchema = `{
   "$schema": "http://json-schema.org/draft-07/schema#",
   "title": "Values",
   "type": "object",
@@ -81,23 +81,23 @@ const subchrtSchema = `{
 `
 
 func TestValidateAgainstSchema(t *testing.T) {
-	subchrtJSON := []byte(subchrtSchema)
-	subchrt := &chart.Chart{
+	subchartJSON := []byte(subchartSchema)
+	subchart := &chart.Chart{
 		Metadata: &chart.Metadata{
-			Name: "subchrt",
+			Name: "subchart",
 		},
-		Schema: subchrtJSON,
+		Schema: subchartJSON,
 	}
 	chrt := &chart.Chart{
 		Metadata: &chart.Metadata{
 			Name: "chrt",
 		},
 	}
-	chrt.AddDependency(subchrt)
+	chrt.AddDependency(subchart)
 
 	vals := map[string]interface{}{
 		"name": "John",
-		"subchrt": map[string]interface{}{
+		"subchart": map[string]interface{}{
 			"age": 25,
 		},
 	}
@@ -108,23 +108,23 @@ func TestValidateAgainstSchema(t *testing.T) {
 }
 
 func TestValidateAgainstSchemaNegative(t *testing.T) {
-	subchrtJSON := []byte(subchrtSchema)
-	subchrt := &chart.Chart{
+	subchartJSON := []byte(subchartSchema)
+	subchart := &chart.Chart{
 		Metadata: &chart.Metadata{
-			Name: "subchrt",
+			Name: "subchart",
 		},
-		Schema: subchrtJSON,
+		Schema: subchartJSON,
 	}
 	chrt := &chart.Chart{
 		Metadata: &chart.Metadata{
 			Name: "chrt",
 		},
 	}
-	chrt.AddDependency(subchrt)
+	chrt.AddDependency(subchart)
 
 	vals := map[string]interface{}{
-		"name":    "John",
-		"subchrt": map[string]interface{}{},
+		"name":     "John",
+		"subchart": map[string]interface{}{},
 	}
 
 	var errString string
@@ -134,7 +134,7 @@ func TestValidateAgainstSchemaNegative(t *testing.T) {
 		errString = err.Error()
 	}
 
-	expectedErrString := `subchrt:
+	expectedErrString := `subchart:
 - (root): age is required
 `
 	if errString != expectedErrString {
diff --git a/pkg/chartutil/save_test.go b/pkg/chartutil/save_test.go
index 8941d0368..f367d42eb 100644
--- a/pkg/chartutil/save_test.go
+++ b/pkg/chartutil/save_test.go
@@ -17,7 +17,10 @@ limitations under the License.
 package chartutil
 
 import (
+	"archive/tar"
 	"bytes"
+	"compress/gzip"
+	"io"
 	"io/ioutil"
 	"os"
 	"path"
@@ -25,6 +28,7 @@ import (
 	"regexp"
 	"strings"
 	"testing"
+	"time"
 
 	"helm.sh/helm/v3/pkg/chart"
 	"helm.sh/helm/v3/pkg/chart/loader"
@@ -99,6 +103,85 @@ func Indent(n int, text string) string {
 	return startOfLine.ReplaceAllLiteralString(text, indentation)
 }
 
+func TestSavePreservesTimestamps(t *testing.T) {
+	// Test executes so quickly that if we don't subtract a second, the
+	// check will fail because `initialCreateTime` will be identical to the
+	// written timestamp for the files.
+	initialCreateTime := time.Now().Add(-1 * time.Second)
+
+	tmp, err := ioutil.TempDir("", "helm-")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmp)
+
+	c := &chart.Chart{
+		Metadata: &chart.Metadata{
+			APIVersion: chart.APIVersionV1,
+			Name:       "ahab",
+			Version:    "1.2.3.4",
+		},
+		Values: map[string]interface{}{
+			"imageName": "testimage",
+			"imageId":   42,
+		},
+		Files: []*chart.File{
+			{Name: "scheherazade/shahryar.txt", Data: []byte("1,001 Nights")},
+		},
+		Schema: []byte("{\n  \"title\": \"Values\"\n}"),
+	}
+
+	where, err := Save(c, tmp)
+	if err != nil {
+		t.Fatalf("Failed to save: %s", err)
+	}
+
+	allHeaders, err := retrieveAllHeadersFromTar(where)
+	if err != nil {
+		t.Fatalf("Failed to parse tar: %v", err)
+	}
+
+	for _, header := range allHeaders {
+		if header.ModTime.Before(initialCreateTime) {
+			t.Fatalf("File timestamp not preserved: %v", header.ModTime)
+		}
+	}
+}
+
+// We could refactor `load.go` to use this `retrieveAllHeadersFromTar` function
+// as well, so we are not duplicating components of the code which iterate
+// through the tar.
+func retrieveAllHeadersFromTar(path string) ([]*tar.Header, error) {
+	raw, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer raw.Close()
+
+	unzipped, err := gzip.NewReader(raw)
+	if err != nil {
+		return nil, err
+	}
+	defer unzipped.Close()
+
+	tr := tar.NewReader(unzipped)
+	headers := []*tar.Header{}
+	for {
+		hd, err := tr.Next()
+		if err == io.EOF {
+			break
+		}
+
+		if err != nil {
+			return nil, err
+		}
+
+		headers = append(headers, hd)
+	}
+
+	return headers, nil
+}
+
 func TestSaveDir(t *testing.T) {
 	tmp, err := ioutil.TempDir("", "helm-")
 	if err != nil {
diff --git a/pkg/chartutil/testdata/subpop/charts/subchart1/values.yaml b/pkg/chartutil/testdata/subpop/charts/subchart1/values.yaml
index 72d3fa5c8..a974e316a 100644
--- a/pkg/chartutil/testdata/subpop/charts/subchart1/values.yaml
+++ b/pkg/chartutil/testdata/subpop/charts/subchart1/values.yaml
@@ -23,7 +23,7 @@ overridden-chartA:
   SCAbool: true
   SCAfloat: 3.14
   SCAint: 100
-  SCAstring: "jabathehut"
+  SCAstring: "jabbathehut"
   SC1extra3: true
 
 imported-chartA-B:
diff --git a/pkg/chartutil/values_test.go b/pkg/chartutil/values_test.go
index a3fe7aeac..c95fa503a 100644
--- a/pkg/chartutil/values_test.go
+++ b/pkg/chartutil/values_test.go
@@ -76,7 +76,7 @@ func TestToRenderValues(t *testing.T) {
 		},
 	}
 
-	overideValues := map[string]interface{}{
+	overrideValues := map[string]interface{}{
 		"name": "Haroun",
 		"where": map[string]interface{}{
 			"city": "Baghdad",
@@ -103,7 +103,7 @@ func TestToRenderValues(t *testing.T) {
 		IsInstall: true,
 	}
 
-	res, err := ToRenderValues(c, overideValues, o, nil)
+	res, err := ToRenderValues(c, overrideValues, o, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -275,10 +275,10 @@ chapter:
 	} else if v != "Loomings" {
 		t.Errorf("No error but got wrong value for title: %s\n%v", err, d)
 	}
-	if _, err := d.PathValue("chapter.one.doesntexist"); err == nil {
+	if _, err := d.PathValue("chapter.one.doesnotexist"); err == nil {
 		t.Errorf("Non-existent key should return error: %s\n%v", err, d)
 	}
-	if _, err := d.PathValue("chapter.doesntexist.one"); err == nil {
+	if _, err := d.PathValue("chapter.doesnotexist.one"); err == nil {
 		t.Errorf("Non-existent key in middle of path should return error: %s\n%v", err, d)
 	}
 	if _, err := d.PathValue(""); err == nil {
diff --git a/pkg/cli/environment_test.go b/pkg/cli/environment_test.go
index d6856dd01..fadc2981e 100644
--- a/pkg/cli/environment_test.go
+++ b/pkg/cli/environment_test.go
@@ -29,8 +29,8 @@ func TestEnvSettings(t *testing.T) {
 		name string
 
 		// input
-		args   string
-		envars map[string]string
+		args    string
+		envvars map[string]string
 
 		// expected values
 		ns, kcontext string
@@ -47,17 +47,17 @@ func TestEnvSettings(t *testing.T) {
 			debug: true,
 		},
 		{
-			name:   "with envvars set",
-			envars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns"},
-			ns:     "yourns",
-			debug:  true,
+			name:    "with envvars set",
+			envvars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns"},
+			ns:      "yourns",
+			debug:   true,
 		},
 		{
-			name:   "with flags and envvars set",
-			args:   "--debug --namespace=myns",
-			envars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns"},
-			ns:     "myns",
-			debug:  true,
+			name:    "with flags and envvars set",
+			args:    "--debug --namespace=myns",
+			envvars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns"},
+			ns:      "myns",
+			debug:   true,
 		},
 	}
 
@@ -65,7 +65,7 @@ func TestEnvSettings(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			defer resetEnv()()
 
-			for k, v := range tt.envars {
+			for k, v := range tt.envvars {
 				os.Setenv(k, v)
 			}
 
diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go
index dd83c3dc2..ea235c13f 100644
--- a/pkg/downloader/manager_test.go
+++ b/pkg/downloader/manager_test.go
@@ -211,7 +211,7 @@ func TestUpdateBeforeBuild(t *testing.T) {
 		Metadata: &chart.Metadata{
 			Name:       "with-dependency",
 			Version:    "0.1.0",
-			APIVersion: "v1",
+			APIVersion: "v2",
 			Dependencies: []*chart.Dependency{{
 				Name:       d.Metadata.Name,
 				Version:    ">=0.1.0",
@@ -285,7 +285,7 @@ func checkBuildWithOptionalFields(t *testing.T, chartName string, dep chart.Depe
 		Metadata: &chart.Metadata{
 			Name:         chartName,
 			Version:      "0.1.0",
-			APIVersion:   "v1",
+			APIVersion:   "v2",
 			Dependencies: []*chart.Dependency{&dep},
 		},
 	}
diff --git a/pkg/kube/resource_test.go b/pkg/kube/resource_test.go
index 2e13c3253..3c906ceca 100644
--- a/pkg/kube/resource_test.go
+++ b/pkg/kube/resource_test.go
@@ -37,6 +37,10 @@ func TestResourceList(t *testing.T) {
 	r1 = []*resource.Info{info("foo"), info("bar")}
 	r2 = []*resource.Info{info("bar")}
 
+	if r1.Get(info("bar")).Mapping.Resource.Resource != "pod" {
+		t.Error("expected get pod")
+	}
+
 	diff := r1.Difference(r2)
 	if len(diff) != 1 {
 		t.Error("expected 1 result")
diff --git a/pkg/plugin/installer/http_installer_test.go b/pkg/plugin/installer/http_installer_test.go
index 89884f107..cfa2e4cbe 100644
--- a/pkg/plugin/installer/http_installer_test.go
+++ b/pkg/plugin/installer/http_installer_test.go
@@ -234,12 +234,12 @@ func TestExtract(t *testing.T) {
 	gz.Close()
 	// END tarball creation
 
-	extr, err := NewExtractor(source)
+	extractor, err := NewExtractor(source)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	if err = extr.Extract(&buf, tempDir); err != nil {
+	if err = extractor.Extract(&buf, tempDir); err != nil {
 		t.Errorf("Did not expect error but got error: %v", err)
 	}
 
diff --git a/pkg/releaseutil/kind_sorter_test.go b/pkg/releaseutil/kind_sorter_test.go
index 93d8ae782..4747e8252 100644
--- a/pkg/releaseutil/kind_sorter_test.go
+++ b/pkg/releaseutil/kind_sorter_test.go
@@ -40,7 +40,7 @@ func TestKindSorter(t *testing.T) {
 			Head: &SimpleHead{Kind: "ClusterRoleBindingList"},
 		},
 		{
-			Name: "e",
+			Name: "f",
 			Head: &SimpleHead{Kind: "ConfigMap"},
 		},
 		{
@@ -84,11 +84,11 @@ func TestKindSorter(t *testing.T) {
 			Head: &SimpleHead{Kind: "NetworkPolicy"},
 		},
 		{
-			Name: "f",
+			Name: "g",
 			Head: &SimpleHead{Kind: "PersistentVolume"},
 		},
 		{
-			Name: "g",
+			Name: "h",
 			Head: &SimpleHead{Kind: "PersistentVolumeClaim"},
 		},
 		{
@@ -132,7 +132,7 @@ func TestKindSorter(t *testing.T) {
 			Head: &SimpleHead{Kind: "RoleBindingList"},
 		},
 		{
-			Name: "d",
+			Name: "e",
 			Head: &SimpleHead{Kind: "Secret"},
 		},
 		{
@@ -140,7 +140,7 @@ func TestKindSorter(t *testing.T) {
 			Head: &SimpleHead{Kind: "Service"},
 		},
 		{
-			Name: "h",
+			Name: "d",
 			Head: &SimpleHead{Kind: "ServiceAccount"},
 		},
 		{
@@ -166,8 +166,8 @@ func TestKindSorter(t *testing.T) {
 		order       KindSortOrder
 		expected    string
 	}{
-		{"install", InstallOrder, "aAbcC3de1fgh2iIjJkKlLmnopqrxstuvw!"},
-		{"uninstall", UninstallOrder, "wvmutsxrqponLlKkJjIi2hgf1ed3CcbAa!"},
+		{"install", InstallOrder, "aAbcC3def1gh2iIjJkKlLmnopqrxstuvw!"},
+		{"uninstall", UninstallOrder, "wvmutsxrqponLlKkJjIi2hg1fed3CcbAa!"},
 	} {
 		var buf bytes.Buffer
 		t.Run(test.description, func(t *testing.T) {
@@ -185,8 +185,8 @@ func TestKindSorter(t *testing.T) {
 	}
 }
 
-// TestKindSorterSubSort verifies manifests of same kind are also sorted alphanumeric
-func TestKindSorterSubSort(t *testing.T) {
+// TestKindSorterKeepOriginalOrder verifies manifests of same kind are kept in original order
+func TestKindSorterKeepOriginalOrder(t *testing.T) {
 	manifests := []Manifest{
 		{
 			Name: "a",
@@ -230,8 +230,8 @@ func TestKindSorterSubSort(t *testing.T) {
 		order       KindSortOrder
 		expected    string
 	}{
-		// expectation is sorted by kind (unknown is last) and then sub sorted alphabetically within each group
-		{"cm,clusterRole,clusterRoleBinding,Unknown,Unknown2", InstallOrder, "01Aa!zu1u2t3"},
+		// expectation is sorted by kind (unknown is last) and within each group of same kind, the order is kept
+		{"cm,clusterRole,clusterRoleBinding,Unknown,Unknown2", InstallOrder, "01aAz!u2u1t3"},
 	} {
 		var buf bytes.Buffer
 		t.Run(test.description, func(t *testing.T) {
@@ -245,3 +245,24 @@ func TestKindSorterSubSort(t *testing.T) {
 		})
 	}
 }
+
+func TestKindSorterNamespaceAgainstUnknown(t *testing.T) {
+	unknown := Manifest{
+		Name: "a",
+		Head: &SimpleHead{Kind: "Unknown"},
+	}
+	namespace := Manifest{
+		Name: "b",
+		Head: &SimpleHead{Kind: "Namespace"},
+	}
+
+	manifests := []Manifest{unknown, namespace}
+	sortByKind(manifests, InstallOrder)
+
+	expectedOrder := []Manifest{namespace, unknown}
+	for i, manifest := range manifests {
+		if expectedOrder[i].Name != manifest.Name {
+			t.Errorf("Expected %s, got %s", expectedOrder[i].Name, manifest.Name)
+		}
+	}
+}
diff --git a/pkg/repo/chartrepo_test.go b/pkg/repo/chartrepo_test.go
index 9f4273682..c6b227acf 100644
--- a/pkg/repo/chartrepo_test.go
+++ b/pkg/repo/chartrepo_test.go
@@ -237,7 +237,7 @@ func verifyIndex(t *testing.T, actual *IndexFile) {
 				t.Errorf("Expected %q, got %q", e.Version, g.Version)
 			}
 			if len(g.Keywords) != 3 {
-				t.Error("Expected 3 keyrwords.")
+				t.Error("Expected 3 keywords.")
 			}
 			if len(g.Maintainers) != 2 {
 				t.Error("Expected 2 maintainers.")
diff --git a/pkg/repo/index_test.go b/pkg/repo/index_test.go
index bc0b45e2c..5dbd5e551 100644
--- a/pkg/repo/index_test.go
+++ b/pkg/repo/index_test.go
@@ -17,14 +17,19 @@ limitations under the License.
 package repo
 
 import (
+	"bufio"
+	"bytes"
 	"io/ioutil"
 	"net/http"
 	"os"
+	"path/filepath"
+	"sort"
 	"strings"
 	"testing"
 
 	"helm.sh/helm/v3/pkg/cli"
 	"helm.sh/helm/v3/pkg/getter"
+	"helm.sh/helm/v3/pkg/helmpath"
 
 	"helm.sh/helm/v3/pkg/chart"
 )
@@ -131,7 +136,7 @@ func TestMerge(t *testing.T) {
 
 	if len(ind1.Entries) != 2 {
 		t.Errorf("Expected 2 entries, got %d", len(ind1.Entries))
-		vs := ind1.Entries["dreadnaught"]
+		vs := ind1.Entries["dreadnought"]
 		if len(vs) != 2 {
 			t.Errorf("Expected 2 versions, got %d", len(vs))
 		}
@@ -178,6 +183,18 @@ func TestDownloadIndexFile(t *testing.T) {
 			t.Fatalf("Index %q failed to parse: %s", testfile, err)
 		}
 		verifyLocalIndex(t, i)
+
+		// Check that charts file is also created
+		idx = filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name))
+		if _, err := os.Stat(idx); err != nil {
+			t.Fatalf("error finding created charts file: %#v", err)
+		}
+
+		b, err = ioutil.ReadFile(idx)
+		if err != nil {
+			t.Fatalf("error reading charts file: %#v", err)
+		}
+		verifyLocalChartsFile(t, b, i)
 	})
 
 	t.Run("should not decode the path in the repo url while downloading index", func(t *testing.T) {
@@ -224,6 +241,18 @@ func TestDownloadIndexFile(t *testing.T) {
 			t.Fatalf("Index %q failed to parse: %s", testfile, err)
 		}
 		verifyLocalIndex(t, i)
+
+		// Check that charts file is also created
+		idx = filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name))
+		if _, err := os.Stat(idx); err != nil {
+			t.Fatalf("error finding created charts file: %#v", err)
+		}
+
+		b, err = ioutil.ReadFile(idx)
+		if err != nil {
+			t.Fatalf("error reading charts file: %#v", err)
+		}
+		verifyLocalChartsFile(t, b, i)
 	})
 }
 
@@ -322,6 +351,24 @@ func verifyLocalIndex(t *testing.T, i *IndexFile) {
 	}
 }
 
+func verifyLocalChartsFile(t *testing.T, chartsContent []byte, indexContent *IndexFile) {
+	var expected, real []string
+	for chart := range indexContent.Entries {
+		expected = append(expected, chart)
+	}
+	sort.Strings(expected)
+
+	scanner := bufio.NewScanner(bytes.NewReader(chartsContent))
+	for scanner.Scan() {
+		real = append(real, scanner.Text())
+	}
+	sort.Strings(real)
+
+	if strings.Join(expected, " ") != strings.Join(real, " ") {
+		t.Errorf("Cached charts file content unexpected. Expected:\n%s\ngot:\n%s", expected, real)
+	}
+}
+
 func TestIndexDirectory(t *testing.T) {
 	dir := "testdata/repository"
 	index, err := IndexDirectory(dir, "http://localhost:8080")
@@ -361,26 +408,6 @@ func TestIndexDirectory(t *testing.T) {
 	}
 }
 
-func TestLoadUnversionedIndex(t *testing.T) {
-	data, err := ioutil.ReadFile("testdata/unversioned-index.yaml")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	ind, err := loadUnversionedIndex(data)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if l := len(ind.Entries); l != 2 {
-		t.Fatalf("Expected 2 entries, got %d", l)
-	}
-
-	if l := len(ind.Entries["mysql"]); l != 3 {
-		t.Fatalf("Expected 3 mysql versions, got %d", l)
-	}
-}
-
 func TestIndexAdd(t *testing.T) {
 	i := NewIndexFile()
 	i.Add(&chart.Metadata{Name: "clipper", Version: "0.1.0"}, "clipper-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890")
diff --git a/pkg/repo/testdata/unversioned-index.yaml b/pkg/repo/testdata/unversioned-index.yaml
deleted file mode 100644
index 1d814c7ae..000000000
--- a/pkg/repo/testdata/unversioned-index.yaml
+++ /dev/null
@@ -1,60 +0,0 @@
-memcached-0.1.0:
-  name: memcached
-  url: https://mumoshu.github.io/charts/memcached-0.1.0.tgz
-  created: 2016-08-04 02:05:02.259205055 +0000 UTC
-  checksum: ce9b76576c4b4eb74286fa30a978c56d69e7a522
-  chartfile:
-    name: memcached
-    home: http://https://hub.docker.com/_/memcached/
-    sources: []
-    version: 0.1.0
-    description: A simple Memcached cluster
-    keywords: []
-    maintainers:
-      - name: Matt Butcher
-        email: mbutcher@deis.com
-mysql-0.2.0:
-  name: mysql
-  url: https://mumoshu.github.io/charts/mysql-0.2.0.tgz
-  created: 2016-08-04 00:42:47.517342022 +0000 UTC
-  checksum: aa5edd2904d639b0b6295f1c7cf4c0a8e4f77dd3
-  chartfile:
-    name: mysql
-    home: https://www.mysql.com/
-    sources: []
-    version: 0.2.0
-    description: Chart running MySQL.
-    keywords: []
-    maintainers:
-      - name: Matt Fisher
-        email: mfisher@deis.com
-mysql-0.2.1:
-  name: mysql
-  url: https://mumoshu.github.io/charts/mysql-0.2.1.tgz
-  created: 2016-08-04 02:40:29.717829534 +0000 UTC
-  checksum: 9d9f056171beefaaa04db75680319ca4edb6336a
-  chartfile:
-    name: mysql
-    home: https://www.mysql.com/
-    sources: []
-    version: 0.2.1
-    description: Chart running MySQL.
-    keywords: []
-    maintainers:
-      - name: Matt Fisher
-        email: mfisher@deis.com
-mysql-0.2.2:
-  name: mysql
-  url: https://mumoshu.github.io/charts/mysql-0.2.2.tgz
-  created: 2016-08-04 02:40:29.71841952 +0000 UTC
-  checksum: 6d6810e76a5987943faf0040ec22990d9fb141c7
-  chartfile:
-    name: mysql
-    home: https://www.mysql.com/
-    sources: []
-    version: 0.2.2
-    description: Chart running MySQL.
-    keywords: []
-    maintainers:
-      - name: Matt Fisher
-        email: mfisher@deis.com