When switching between multiple Xcode versions one way to globally
update the version you want to use is by running
xcode-select like this:
sudo xcode-select -s /Applications/Xcode-12.5.1.app
Then, if you want to automatically accept Xcode's license, and install any extra packages it requires (which should only be required the for the first time you run a new version), you can run:
sudo xcodebuild -runFirstLaunch
This works fine locally, but when updating remote CI machines, entering
the password can be troublesome. Furthermore if you want to support
having CI machines automatically switch between Xcode versions when
testing upcoming changes, you may not have the opportunity to be
prompted at all. Lucky for us, the
sudoers file format,
which configures the
sudo command, allows us to skip password entry
for specific commands with a bit of configuration.
The easiest way to edit this configuration is by running:
This opens the default
/etc/sudoers configuration file in vim. While
we could add our custom configuration here, we can also see the default
configuration that ships with macOS contains this line:
sudo to load all the files in
configuration as well. Using this knowledge we can nicely separate our
custom configuration, making it easier to overwrite, or remove, in the
future. Separating our custom configuration also makes us less likely to
break the default configuration, potentially leading to major issues.
To setup our custom configuration we can run this command:
echo "%admin ALL=NOPASSWD: /usr/bin/xcode-select,/usr/bin/xcodebuild -runFirstLaunch" | sudo tee /etc/sudoers.d/xcode
Let's break this down2. The
%admin component makes this
configuration apply to all users that are in the
Using this group is probably good enough for this use case, but if you'd
like to restrict this more, you can change this to a your account's
specific username such as
The second component
ALL makes this rule apply to all hosts, I'm not
sure in what context any host besides the current one would take these
rules into account, but
ALL ignores that.
The third component
NOPASSWD is the key piece of this functionality.
This enables us to run the following commands without being prompted for
The last component is the commands we want to allow to be run without a password. There are 2 things to note here.
- We specify just the
xcode-selectbinary, using the absolute path. This allows all subcommands handled by
xcode-selectto be run without a password.
xcodebuildcommand also contains the one subcommand we want to be able to run without a password. Limiting this is important because otherwise you could run
sudo xcodebuild buildwithout a password, which could execute malicious run scripts or do other terrible things. With this argument specified any other invocation of
sudo xcodebuildwill still require a password.
Just like that we no longer have to enter our password when swapping between Xcode versions.