Currently, if you have several updates/installs to do, you have to install one by one, wait for the whole thing to compile after every update/install. It would be better if you could select all the installs/removals/updates you want and then click on "update all"... that way you could save a lot of time.
I would also like to have an option to select a number of packages, and remove them. Every time I start a new project, I'm opening the Package Manager UI and remove some packages one by one, or opening the manifest.json and removing them from there...
I wrote this, but should warn you, it may cause packages or even all project reimport. It's not resolving dependencies, package version is chosen automaticly by Unity's "Client.Add(PackageName)". After execution may need to restart unity Available with btn in Package info and MenuItem "Help / Update All Packages" github: https://github.com/mitay-walle/Unity-PackageManager-Update-All Spoiler: Unsafe solution Code (CSharp): using PackageInfo = UnityEditor.PackageManager.PackageInfo; using UnityEditor.PackageManager.Requests; using UnityEditor.PackageManager.UI; using System.Collections.Generic; using UnityEditor.PackageManager; using UnityEngine.UIElements; using UnityEngine; using UnityEditor; namespace Plugins.Editor { internal class PMUpdateAllBtnExtension : IPackageManagerExtension { public VisualElement CreateExtensionUI() { var btn = new Button(PackageManagerUpdateAllUtility.StartUpdateAll); btn.text = btn.name = "Update All Packages"; return btn; } public void OnPackageSelectionChange(PackageInfo packageInfo) { } public void OnPackageAddedOrUpdated(PackageInfo packageInfo) { } public void OnPackageRemoved(PackageInfo packageInfo) { } } [InitializeOnLoad] public static class PackageManagerUpdateAllUtility { private const bool ADD_BTN = true; private const bool FULL_LOGS = false; const int MAX_ITERATIONS = 50; static int UpdatePackagesCurrentCount = 0; static bool UpdatingSomePackage; static bool UpdatePackagesInProgress; static ListRequest lRequest; static AddRequest aRequest; static readonly List<string> needToUpate = new List<string>(); private static readonly PMUpdateAllBtnExtension extension = new PMUpdateAllBtnExtension(); static PackageManagerUpdateAllUtility() { if (ADD_BTN) { PackageManagerExtensions.RegisterExtension(extension); } // if (FULL_LOGS) Debug.Log("check EditorPrefs"); // UpdatePackagesInProgress = EditorPrefs.GetBool("UpdatePackagesInProgress"); // UpdatePackagesCurrentCount = EditorPrefs.GetInt("UpdatePackagesCurrentCount"); // // if (UpdatePackagesCurrentCount > MAX_ITERATIONS) // { // ForceStop(); // Debug.LogError($"{MAX_ITERATIONS} packages updated, prevent infinite update"); // return; // } // // EditorPrefs.SetInt("UpdatePackagesCurrentCount",UpdatePackagesCurrentCount+1); // // if (UpdatePackagesInProgress && !UpdatingSomePackage) // { // ContinueUpdateAllpackages(); // } } [MenuItem("Help/Update All Packages")] public static void StartUpdateAll() { EditorPrefs.SetBool("UpdatePackagesInProgress", true); UpdatePackagesInProgress = true; ContinueUpdateAllpackages(); } public static void ContinueUpdateAllpackages() { lRequest = Client.List(); // List packages installed for the Project EditorApplication.update += ProgressRequestPackageList; } static void ForceStop() { Debug.LogError("somethnig go wrong!"); EditorApplication.update -= ProgressRequestPackageList; EditorPrefs.SetBool("UpdatePackagesInProgress", true); UpdatePackagesCurrentCount = 0; EditorPrefs.SetInt("UpdatePackagesCurrentCount",0); UpdatePackagesInProgress = true; } static void ProgressRequestPackageList() { if (lRequest == null) { ForceStop(); return; } if (lRequest.IsCompleted) { if (lRequest.Status == StatusCode.Success) { UpdateAll(); } else if (lRequest.Status >= StatusCode.Failure) Debug.LogError(lRequest.Error.message); EditorApplication.update -= ProgressRequestPackageList; } } private static void UpdateAll() { var check = false; needToUpate.Clear(); foreach (var package in lRequest.Result) { if (package.status == PackageStatus.Available) { if (FULL_LOGS) Debug.Log($"'{package.name}' current:{package.version } last compatible:{package.versions.latestCompatible} verified:{package.versions.verified}"); if (package.version == package.versions.latestCompatible || package.version == package.versions.verified) { //Debug.Log($"{package.name} up to date"); } else { if (FULL_LOGS) Debug.Log($"'{package.name}' need update from: {package.version} to: {package.versions.latestCompatible}"); needToUpate.Add(package.name); check = true; } } } if (check) { Debug.Log($"need to Update {needToUpate.Count} packages"); CheckUpdateRequests(); EditorApplication.update += CheckUpdateRequests; } else { Debug.Log($"all packages are up to date!"); } } private static void CheckUpdateRequests() { UpdatingSomePackage = false; if (aRequest == null) { // update first if (FULL_LOGS) Debug.Log($"update first: {needToUpate[0]}"); aRequest = Client.Add(needToUpate[0]); return; } if (!aRequest.IsCompleted) { UpdatingSomePackage = true; return; } //process update result if (FULL_LOGS) Debug.Log($"process update result: {aRequest.Result.name}"); if (aRequest.Status == StatusCode.Success) { Debug.Log($"{aRequest.Result.name} updated to {aRequest.Result.version}"); } if (aRequest.Status >= StatusCode.Failure) { Debug.LogError(aRequest.Error.message); } needToUpate.Remove(aRequest.Result.name); if (needToUpate.Count > 0) { //update next if (FULL_LOGS) Debug.Log($"update next: {needToUpate[0]}"); aRequest = Client.Add(needToUpate[0]); } else { // finish Debug.Log($"finish updating all packages"); EditorApplication.update -= CheckUpdateRequests; EditorPrefs.SetBool("UpdatePackagesInProgress", false); UpdatePackagesInProgress = false; } } } }
Actually I just realised this feature is now in 2022.1 I just checked! You can multi select packages with shift key and perform similar actions on them all if possible e.g. update or install packages https://unity.com/roadmap/unity-platform/pipeline-integrations!