Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use mas for Mac App Store automation #11

Closed
geerlingguy opened this issue Mar 28, 2016 · 13 comments
Closed

Use mas for Mac App Store automation #11

geerlingguy opened this issue Mar 28, 2016 · 13 comments

Comments

@geerlingguy
Copy link
Owner

See: https://github.com/argon/mas

This would be nice to get even the Mac App Store stuff automated. Or maybe just a second playbook that you can run once authenticated, something like that.

@geerlingguy
Copy link
Owner Author

geerlingguy commented Jul 5, 2016

See: https://github.com/TravisCarden/dotfiles/blob/master/playbooks/tasks/mac-app-store.yml

Idempotent example:

- name: Install Mac App Store apps.
  shell: mas list | grep {{ item }} || mas install {{ item }}
  with_items:
    - 407963104 # Pixelmator
    - ...
  register: result
  changed_when: result.stdout.find('Installed') != -1

h/t to @TravisCarden

@fubarhouse
Copy link

+1.

@fubarhouse
Copy link

fubarhouse commented Oct 24, 2016

Here's a small variation, which improves readability.
Tested and verified, so I'm not sure what's holding this one back.

vars/main.yml

#
# Mac Apple Store
#
# Apps to install from the app store.
# Array of App ID's will only validate.
#

mac_store_apps:
  - name: Blackmagic Disk Speed Test
    id: 425264550

main.yml

    - include: tasks/mac-apple-store.yml
      when: '"mas" in homebrew_installed_packages'

tasks/mac-apple-store.yml

- name: Mac Apple Store | Signing out
  shell: "mas signout"
  register: mac_account
  when: app_store_email is defined and app_store_password is defined

- name: Mac Apple Store | Signing in.
  shell: "mas signin \"{{ app_store_email }}\" \"{{ app_store_password }}\""
  register: result
  when: app_store_email is defined and app_store_password is defined and mac_account is defined

- name: Mac Apple Store | Install apps.
  shell: mas list | grep "{{ item.id }}" || mas install "{{ item.id }}"
  with_items: "{{ mac_store_apps }}"
  register: result
  changed_when: result.stdout.find('Installed') != -1

- name: Mac Apple Store | Upgrade apps.
  shell: mas list | grep "{{ item.id }}" || mas upgrade "{{ item.id }}"
  with_items: "{{ mac_store_apps }}"
  register: result
  changed_when: result.stdout.find('Installed') != -1

extra vars for signing into mac store

--extra-vars "[email protected] app_store_password=xyz"

This modification changes the structure of the array of processed items, to show the name as well as the mac id. The name isn't actually used by Ansible but it serves as a valuable non-comment entry to authors to identify what's what.

Also added is an easy way to sign the user in, with the assistance of additional variables declared on the command line.

This could all be a new role though, if you didn't want the integration aspects.

It has been tested with and without variable input, and all cases where a fail is possible have been eliminated here.

@geerlingguy
Copy link
Owner Author

@fubarhouse - Thanks for your work on this—one of the last components would be to document how to get mas initialized, or if it can be done automatically during the playbook run, maybe using an Ansible prompt to get the mas username/password...

I wouldn't want the playbook to hang the first time it's run because mas was just installed and isn't able to actually connect to the App store.

@fubarhouse
Copy link

fubarhouse commented Oct 26, 2016

Revision 2

Changes as requested, see full list of changes from the master below.

For documentation purposes, any user can turn the entire functionality off by setting install_mas_products to be false.

Let me know if you're happy and I can create a PR.

Observations

  • MAS will request a username/password using the Apple store on OSX (not command-line) when you're requesting a download but not logged in, it will not in fact hang on input at the command line.
  • Logic is in place as to not break automated testing, and username/password can be specified. If no input is entered the tasks will not execute. If the variables are entered using --extra-vars it will not prompt for entry.

vars/main.yml

install_mas_products: yes
#
# Mac Apple Store
#
# Apps to install from the app store.
# Array of App ID's will only validate.
#

mac_store_apps:
  - name: BlackMagic Disk Speed test
    id: 425264550
  - name: Microsoft OneDrive
    id: 823766827

main.yml

  vars_prompt:
  - name: app_store_email
    prompt: Mac Apple Store ID:
    private: no
    when: app_store_email is undefined
  - name: app_store_password
    prompt: Mac Apple Store Password:
    private: yes
    when: app_store_password is undefined
    - include: tasks/mac-apple-store.yml
      when: install_mas_products

tasks/mac-apple-store.yml

---
- name: Mac Apple Store | Ensure MAS is installed
  homebrew:
    name: mas
    state: present

- name: Mac Apple Store | Signing out
  shell: "mas signout"
  register: mac_account
  when: app_store_email is defined and app_store_email != '' and app_store_password is defined and app_store_password != ''

- name: Mac Apple Store | Signing in.
  shell: "mas signin \"{{ app_store_email }}\" \"{{ app_store_password }}\""
  register: result
  when: app_store_email is defined and app_store_email != '' and app_store_password is defined and app_store_password != '' and mac_account is defined

- name: Mac Apple Store | Install apps.
  shell: mas list | grep "{{ item.id }}" || mas install "{{ item.id }}"
  with_items: "{{ mac_store_apps }}"
  register: result
  changed_when: result.stdout.find('Installed') != -1
  when: app_store_email is defined and app_store_email != '' and app_store_password is defined and app_store_password != '' and mac_account is defined

- name: Mac Apple Store | Upgrade apps.
  shell: mas list | grep "{{ item.id }}" || mas upgrade "{{ item.id }}"
  with_items: "{{ mac_store_apps }}"
  register: result
  changed_when: result.stdout.find('Installed') != -1
  when: app_store_email is defined and app_store_email != '' and app_store_password is defined and app_store_password != '' and mac_account is defined

@geerlingguy
Copy link
Owner Author

A few notes:

  1. I've merged the above changes (though architected a little differently—but still giving @fubarhouse the commit credit) into a new role, https://github.com/geerlingguy/ansible-role-mas
  2. The mas cli seems to (thankfully) manually prompt an App Store login if it's not already signed in (and Ansible just sits and waits while that happens). Therefore the sign in process isn't quite as annoying as I thought it would be. Though I may add the ability to sign in using vars_prompt in the future.
  3. You can watch the install progress inside the Mac App Store while Ansible is doing it's thing. Neat!

I'll close this out once I've verified the role and integration with this playbook are working correctly.

@geerlingguy
Copy link
Owner Author

(This is all predicated by my finally getting a new work laptop today, and deciding it's better to spend 30 minutes automating the app install instead of spending 5 minutes clicking all those install buttons one by one :P).

@geerlingguy
Copy link
Owner Author

Ooh, purty...

mas-install

@beejhuff
Copy link

beejhuff commented Dec 5, 2016

Jeff - first thanks for all your amazing work on Ansible - I've found your books and code here invaluable :) Quick question - this role presumes that I've already identified the ID's for any of the Applications I want to install via the App Store, correct? It doesn't appear to be using MAS's query functionality to lookup anything, but I wanted to check before I dove in...

@geerlingguy
Copy link
Owner Author

@beejhuff - Correct. I've added some documentation on the MAS role readme—basically you can run mas list to view already-installed apps on a computer you've already set up, and you can use mas search [App Name Here] to find IDs for apps not installed.

@geerlingguy
Copy link
Owner Author

I'm running a final test on my brand new (2015) retina MBP now; once that's done I'll be pushing up the changes to this repo, along with a little more documentation.

@aquintiliano
Copy link

is it bypassing the 2FA of Apple Store? if yes, how do you do it?

@fubarhouse
Copy link

@aquintiliano, it does not. It'll bring up a login dialog box.

fubarhouse pushed a commit to fubarhouse/mac-dev-playbook that referenced this issue Jun 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants