Thanks to visit codestin.com
Credit goes to Github.com

Skip to content

Conversation

@nmclaren
Copy link

Description

This PR adds a new ignore command that allows users to exclude specific apps or app versions from updates. Users can ignore individual versions or all versions of an app, with the ignore list persisting between sessions.

Motivation and Context

Users need the ability to prevent certain apps from being updated, either permanently or for specific versions. Common use cases:

  • Skip problematic versions with known bugs
  • Maintain compatibility with specific app versions
  • Prevent unwanted feature changes in newer versions
  • Control update bandwidth and timing

How Has This Been Tested?

  • βœ… Added 30 comprehensive tests (12 command, 9 controller, 9 model)
  • βœ… All 45 tests passing (15 existing + 30 new)
  • βœ… Tested on macOS 14+ (arm64)
  • βœ… Verified multiple consecutive runs for stability
  • βœ… Confirmed CI compatibility with existing test infrastructure

Test coverage includes:

  • Version-specific and all-versions ignores
  • Conflict detection and user prompts
  • Parentheses stripping bug fix
  • JSON persistence and serialization
  • Thread-safe actor operations

Command line examples:

# Add version-specific ignore
$ mas ignore add 497799835 --version 1.2.3
Ignoring 497799835 version 1.2.3

# List ignores
$ mas ignore list
497799835  1.2.3
408981434  (all versions)

# Conflict resolution
$ mas ignore add 497799835
Warning: App 497799835 already has specific version(s) ignored: 1.2.3
Replace with all-versions ignore? [Y/n]: y
Replaced version-specific ignores with all-versions ignore

# Integration with update
$ mas outdated
497799835  Xcode  (15.1 -> 15.2)

$ mas ignore add 497799835 --version 15.2
$ mas outdated
# Empty - ignored!

Types of changes

  • New feature (non-breaking change which adds functionality)

Additional Notes

Implementation Details

  • Uses Swift actors for thread-safe ignore list management
  • Persists to ~/Library/Application Support/mas/ignore.json
  • Integrates seamlessly with existing update and outdated commands
  • No breaking changes to existing functionality

Files Changed

Added (6 files):

  • Sources/mas/Commands/Ignore.swift - Command implementations
  • Sources/mas/Controllers/IgnoreList.swift - Ignore list manager
  • Sources/mas/Models/IgnoreEntry.swift - Data model
  • Tests/MASTests/Commands/MASTests+Ignore.swift - Command tests
  • Tests/MASTests/Controllers/MASTests+IgnoreList.swift - Controller tests
  • Tests/MASTests/Models/MASTests+IgnoreEntry.swift - Model tests

Modified (2 files):

  • Sources/mas/Commands/OutdatedAppCommand.swift - Added filtering
  • Sources/mas/Commands/MAS.swift - Registered subcommand

Usage Documentation

OVERVIEW: Manage ignored apps and versions

USAGE: mas ignore <subcommand>

SUBCOMMANDS:
  add      Add an app or app version to the ignore list
  remove   Remove an app or app version from the ignore list
  list     List all ignored apps and versions
  clear    Clear all ignored apps and versions

All subcommands include comprehensive help via mas ignore <subcommand> --help

- use `mas ignore` and subcommands to manage adamid (or adamid + version number) ignore list
- ignored adamid/adamid+version combinations in the list are ignored by `mas upgrade` and `mas outdated` commands only
- includes new tests for the new functionality
@rgoldberg
Copy link
Member

rgoldberg commented Dec 18, 2025

@nmclaren Thanks for the PR submission. I haven't had time to read it through completely, but a few high-level notes:

  1. Ignoring is a subset of pinning, which is a subset of version inclusion/exclusion; I'd like to support full inclusion/exclusion, not just ignoring. See Version pinning / ignoringΒ #386. Maybe your code does version pinning inclusion/exclusion, as I haven't had a chance to read it all.
  2. I was planning on configuring version inclusion/exclusion via a generalized configuration system. See Configuration / Config / Settings / Preferences systemΒ #838.
    1. Apple recently released Swift Configuration, which would be nice to use.
    2. Unfortunately, that requires Swift 6.2, which cannot be built on macOS 14, which mas must support until Homebrew Core either stops building bottles for macOS 14 (presumably when Apple stops supporting macOS 14, presumably in the fall of 2026), or supports OS version cross builds (where, e.g., Homebrew Core could build bottles for macOS 14 on macOS 26 instead of on macOS 14). I had though about trying to contribute cross build support to Homebrew, if I finished other higher-priority mas & related work before Homebrew stopped building macOS 14 bottles.
  3. A notification system to inform users of the new feature would also be nice. See Advice / Alert / Hint / Info / Notice / Notification / Tip systemΒ #839. That would be based on Configuration / Config / Settings / Preferences systemΒ #838.
  4. I'll make a few comments on some of the PR code.
  5. Please discuss any potential changes to the PR before you implement anything; I don't want you to waste your time on anything if I might not be able to accept it
  6. Before you submit other features / bug fixes in the future, please feel free to discuss in an existing issue or in a new issue opened by yourself. That would allow me to share my thoughts & development plans, so we can collaboratively determine the best approach before you spend time on a PR. e.g., maybe we should:
    1. try to update Homebrew to support cross builds so we can use Swift Configuration
    2. if 1 isn't feasible, fork Swift Configuration to work with Swift 6.0 until mas no longer needs to build on macOS 14
    3. use a different configuration library
    4. support full version inclusion/exclusion
    5. coordinate large-scale PRs; if I have a large PR pending, you might want to delay starting work on a PR until after I've merged it, to avoid dealing with merge conflicts
    6. etc.

What are your thoughts about the options listed above?

@rgoldberg
Copy link
Member

rgoldberg commented Dec 18, 2025

@nmclaren Instead of comments on the code, some general feedback:

  1. There are some lint violations. You can run Scripts/lint to see the violations. Scripts/format will fix some of the violations. mas uses both SwiftFormat & SwiftLint to both lint & format Swift files.
    1. You should probably run Scripts/bootstrap once on your Mac to install all necessary linters & formates from Homebrew Core.
  2. Various documentation & output should be rephrased, but that can be discussed after the design & technical implementation have mainly been finished.

I'll review some more sometime over the next few days.

@nmclaren
Copy link
Author

Thanks for all of the feedback! Let me try and address some points...

  1. re: linting - I'm getting zero lint errors using Scripts/lint and Scripts/format changes nothing on Tahoe 26.2. I did in fact run Scripts/bootstrap ahead of all that, prior to my initial submission. Alas, I'm not sure how to replicate your results without having a system at my disposal with an earlier MacOS release, but if you can advise on that or include what you're seeing, I'll take them into account and try to fix.
Screenshot 2025-12-18 at 11 09 01β€―AM
  1. re: "pinning" - My code does do "pinning" in a sense, as you can ignore all future updates for an adamid or you can specify specific versions to ignore. It's slightly less granular and more user-friendly than what's described in the notes in (Version pinning / ignoringΒ #386), but it does currently only do string matching against adamid. I think adding the ability to use either adamid strings or regex against the app name would be useful, and easy to incorporate. Could even go so far as to wrap your "pin" command design to allow both options, if you're really set on it. In my brain, "ignore" grok's better than "pin". That's my opinion, but of course it's your call, so I defer to you.

  2. re: configuration storage - I have no particular preference where config data is stored. If it works everywhere, then excellent as far as I'm concerned. I have yet to investigate how heavy of a lift it would be to port Swift Configuration as you described, but as a quick-and-easy alternative we could just abstract the config functionality so it could be used by features independently of the mechanism in which data is stored. Any number of low-effort mechanisms could be used to bridge the short gap until MacOS 14 support goes away. That much would not be a ton of work, and that'd fill it out in the short and long term. But.. it might be just as easy to make Swift Configuration 6.2 and be done with it. Either way is reasonable IMHO.

  3. re: notifications/tips - Since this is a CLI, I'm inclined to think it would be better to include in the man page, but putting it more in front of the user might indeed be friendlier. If a notification/tip system were implemented, I would personally like it to provide the tip, and on the next line indicate the commands that could be run to "turn off tips" or "don't show this tip again", again in the interest of user-friendliness. Plenty of flexibility available.

  4. Completely open to discussing any phrasing (or anything else really). Feel free to call out whenever you're ready to.

  5. A little quick background, I've been coding for multiple decades, but this is my first github PR in general. This was a feature that I personally needed to solve a problem as a user with an app that kept updating every mas upgrade run. Certainly open to make any changes better suited for your general user base, just let me know. Cheers!

@rgoldberg
Copy link
Member

rgoldberg commented Dec 19, 2025

Thanks for the detailed replies & the PR submission.

Reply to your 6

You might be able to use the new --accurate flag for both outdated & update/upgrade (they're synonyms; I prefer update because that's the term used by the App Store; I inherited upgrade from prior code).

It should solve problems with non-oudated apps being reported outdated or being updated.

Its drawbacks are:

  1. It is slower (it starts, then cancels a download for each app specified by the arguments, so includes all apps if no app IDs were given).
  2. It might get you rate limited by Apple if you make too many downloads in too short a time. Not sure exactly what their rate limits might be / how they are enforoced.
  3. Concurrent downloads are currently capped to 16, which doesn't seem to have issues, but there were some hangs before the cap was enforced.
  4. You can get some dialogs under certain circumstances, e.g., an app that was installed for a different Apple Account than the one for which you are currently signed into the App Store.
  5. Maybe a few other issues.

If you have already tried --accurate, but experienced problems so can't use it, sorry for inundating you with stuff you already know. If you didn't know about it, that's why I want to create a notification system. But that will wait until after I have a config system, for which I was waiting for Swift 6.2 & not needing to build on macOS 14 for Homebrew Core.

Reply to your 1

I, too, am using macOS 26.2, Xcode 26.2, and all the latest other software,

You didn't get lint errors because you were on main, not on feature_ignore.

I get the following lint errors on feature_ignore:

$ git branch --show-current 
feature_ignore

$ ./Scripts/lint
==> 🚨 Linting mas 4.1.0-49-g8f00000ed-feature_ignore
--> πŸ•Šβ€‹ SwiftFormat
Sources/mas/Commands/Ignore.swift:70:1: error: (indent) Indent code in accordance with the scope level.
Sources/mas/Commands/Ignore.swift:71:1: error: (indent) Indent code in accordance with the scope level.
Sources/mas/Commands/Ignore.swift:71:1: error: (preferKeyPath) Convert trivial map { $0.foo } closures to keyPath-based syntax.
Sources/mas/Controllers/IgnoreList.swift:23:1: error: (indent) Indent code in accordance with the scope level.
Sources/mas/Controllers/IgnoreList.swift:24:1: error: (indent) Indent code in accordance with the scope level.
Sources/mas/Commands/OutdatedAppCommand.swift:72:1: error: (indent) Indent code in accordance with the scope level.
Sources/mas/Commands/OutdatedAppCommand.swift:73:1: error: (indent) Indent code in accordance with the scope level.
Sources/mas/Commands/OutdatedAppCommand.swift:74:1: error: (indent) Indent code in accordance with the scope level.
Sources/mas/Commands/OutdatedAppCommand.swift:75:1: error: (indent) Indent code in accordance with the scope level.
Sources/mas/Commands/OutdatedAppCommand.swift:76:1: error: (indent) Indent code in accordance with the scope level.
Sources/mas/Commands/OutdatedAppCommand.swift:77:1: error: (indent) Indent code in accordance with the scope level.
Source input did not pass lint check.
3/84 files require formatting.
--> πŸ¦… SwiftLint
Tests/MASTests/Models/MASTests+IgnoreEntry.swift:59:49: error: Force Unwrapping Violation: Force unwrapping should be avoided (force_unwrapping)
--> πŸ”¬ SwiftLint Analyze
--> πŸŒ€ Periphery
--> πŸŒ€ Periphery Tests
--> 〽️ Markdown
--> πŸ“ YAML
--> 🌳 Git
--> πŸ’€ Zsh
--> πŸ™ ActionLint
--> 🐚 ShellCheck
--> 🚷 Non-Executables

Other questions

I will think about this all, read your code, and get back to you when I get the chance. Sorry for not having full answers for everything right now.

- Disabled one linter check for force_unwrapping, which is encouraged in the style guide for tests
@sonarqubecloud
Copy link

@nmclaren
Copy link
Author

  • re: wrong branch - ha! You're so right! facepalms self Well that's embarassing. I've reviewed and fixed the linter issues.

  • re: --accurate - Yes, that DOES filter out my problem update, but I don't like the sound of of bumping up against limits unnecessarily. Will take a look at that code when I have free cycles so I understand what's happening better.

  • Other than that, I'll wait for more from you, when time permits. It's a busy time for everyone so no rush. Cheers!

@rgoldberg
Copy link
Member

Thanks for updating the PR.

I myself haven't yet run into rate limits with around 15-20 App Store apps installed.

The just released 4.1.1 fixes up many problems, so --accurate might now be safe for most, or potentially all, users, outside of being slower & possibly showing dialogs under certain circumstances.

Before fixes from 4.1.1 & other versions, some users with hundreds of apps ran into issues that might have been bad concurrency code (inherited from old mas code, but should now be fixed in 4.1.1), concurrent download overload technical issues (possibly fixed by the 16 max concurrent download cap), concurrent download rate limiting issues (possibly fixed by 16 max cap), or duration-based usage rate limiting issues.

Hopefully, only the last would still possibly apply, though it might not even be a problem.

I need to work with someone who has hundreds of apps, or make a testing user and download hundreds of apps to test myself. I'd prefer to do that on a virtual machine than in my main Mac file system, but I haven't setup virtual machines before, so that's another can of worms I'd prefer to open later.

I'm trying to finish up some other mas work that I was already working on before you submitted your PR, and dealing with stuff outside mas, so it might be a bit before I can properly review everything, including thinking through Swift Configuration / a stopgap measure. I'd want any stopgap config storage to be able to be used directly by Swift Configuration once I start using it; I don't want to need to write code that converts from one config storage paradigm to another. Etc.

Thanks again.

@rgoldberg
Copy link
Member

rgoldberg commented Dec 21, 2025

Due to many issues with Xcode < 26, mas will probably require Xcode 26 very soon, which will allow mas to use Swift 6.2, which will allow mas to use Swift Configuration.

The tentative mas road map is (with random small cleanup sprinkled throughout):

  • 4.1.2
    • Fix install / update issues
  • 5.0.0
    • Fix install / update issues
    • Require macOS 13+ to deploy
    • Require Xcode 26+ to build
    • Update code to use Swift 6.2
    • Remove some vestigial "features"
  • 5.1.0
    • Support JSON output
    • Properly tabulate output
    • Maybe support tabular field selection
  • 5.2.0
    • Generate shell completions via SAP
    • Remove lucky
    • Refactor get & install
  • 5.3.0
    • Use Swift Configuration
    • Support ignoring / pinning / including / excluding apps
    • Maybe support mas feature / other notifications

5.1.0, 5.2.0 & 5.3.0 might be reordered if anything gets too difficult (most likely to be shell completion, as I need to submit complex changes to SAP).

I would like to finish 5.0.0, 5.1.0 & 5.2.0 before 5.3.0 because I am already in the middle of working on them

  • 5.0.0 because of all the changes that macOS 26.1, 15.7.2 & 14.8.2 required
  • 5.1.0 because that's what I was working on when macOS 26.1 et al disrupted everything
  • 5.2.0 because I was working on that before 5.1.0, but shelved it due to its increasing complexity as I was sick; working on simpler stuff was much more pleasant then

It will probably be simplest for me to integrate Swift Configuration & to implement ignoring / etc. myself. I will need to understand all the details of Swift Configuration, so no need for you to learn it all, too. The implementation of ignoring, etc. should be simple once Swift Configuration is setup.

I'll happily discuss the feature set for ignoring / etc. once I'm done with the other work, so I can work on it without too much context switching.

Do you mind if I write my solution from the ground up after discussions? I will share with you any PR I write so you can review it.

@nmclaren
Copy link
Author

No problem. Do whatever feels right to you. I'd be happy to review it when the time comes. Cheers!

@rgoldberg
Copy link
Member

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants