-
Notifications
You must be signed in to change notification settings - Fork 2
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
Introduce :overrides
option
#152
Conversation
(spec/def ::members (spec/and (spec/coll-of ::member) | ||
(fn [xs] | ||
(let [ids (->> xs | ||
(map (fn ^{::speced/spec (rcomp count #{0 1})} [x] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(map (fn ^{::speced/spec (rcomp count #{0 1})} [x] | |
(map (speced/fn ^{::speced/spec (rcomp count #{0 1})} [x] |
@@ -22,6 +25,23 @@ so that final users can locate them and configure them." | |||
(check! (spec/keys :req-un [:formatting-stack.protocols.spec.member/id]) | |||
x)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(speced/def-with-doc ::member
"A 'member' of the stack that does something useful: a formatter, linter or processor.
'Strategies' and 'Reporters' are not members - instead they help members accomplish their purpose."
(spec/or :id (spec/keys :req-un [:formatting-stack.protocols.spec.member/id])
;; we are facing a `reify`, which means that formatting-stack is being customized
;; In those cases, an :id is practically useless (since the point of :id is overriding f-s), so no validation needed:
:reify ::reify))
This will work without calling check!
/ valid?
in the spec.
(assert (apply distinct? ids) | ||
"Members should have unique ids")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This spec should be refactored so it leverages clojure.spec more. which improves testing/debugging/extensibility
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will check what can be done. At the very least a pr-str ids
is due
(try | ||
(sut/apply-overrides members overrides) | ||
(catch AssertionError _ | ||
::EXCEPTION)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not rethrow this exception? Currently it'll swallow the error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an are
test case that will expect this ::EXCEPTION
, so these aren't omitted
(that's part of why I put these in caps - to make it more immediately visible that something is both declared and consumed)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we split that are
up, so the ones expecting an exception can use thrown-with-msg?
for a more specific test? (e.g. now any assertionerror will pass)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I wouldn't split the are
- a single are
means more contrast, less apples-vs-oranges etc
Will look into making this are
itself more accurate, should be possible
:in-background? in-background?))) | ||
|
||
(defn lint-branch! [& {:keys [target-branch in-background? reporter] | ||
(defn lint-branch! [& {:keys [target-branch in-background? reporter overrides] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why nest formatters/linters/processors/strategies under override
? They seem direct arguments for lint-branch!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first thing that comes to mind is that the config should be a single map, so that it can become data.
- data (a single hashmap) is simpler than code (a more intrincate invocation consisting of multiple arguments)
- a single hashmap can be (more) easily a resource, a piece of Lein config, etc.
- this is important, as one will want to share config across projects.
- I envision this being accomplished by creating a single dep, containing a .edn as a resource. Zero config or
require
s to be done for consumers: we just discover the presence of such a config file.
- I envision this being accomplished by creating a single dep, containing a .edn as a resource. Zero config or
- this is important, as one will want to share config across projects.
- Hashmaps can be (deep) merged
- Not hard to imagine that people can want a merge of f-s defaults <-> workplace defaults <-> personal defaults.
It's also good to emphasize the notion of overrides as:
- a thing you should be aware of
- if I can pass
:linters
separately, I can be unaware of the existence a deep-merged overrides system - unawareness -> confusion, surprises, etc
- if I can pass
- the sole intended API
- More APIs -> more complexity (surface area for bugs)
{formatter-overrides :formatters | ||
linter-overrides :linters | ||
processor-overrides :processors | ||
{formatters-strategies :formatters | ||
linters-strategies :linters | ||
processors-strategies :processors} :strategies} :overrides}] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we deal with the overrides one level higher e.g. create a fn which applies overrides, then call format!
?
That way format!
does less, and doesn't have to change shape, except for the removal of defaults (which is a good thing imo)
processors | ||
reporter | ||
in-background?]}] | ||
(speced/defn format! [& {:keys [^vector? strategies |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big fan of the factory-concept here. We could assoc the strategies in format!
(they are impl detail anyway), which would remove the need of creating the formatters/etc here, retaining the vectors as params.
third-party-indent-specs
is still an issue, suggestion posted below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could assoc the strategies in format! (they are impl detail anyway)
See my comment beginning with The first thing that comes to mind [...]
|
||
(speced/defn default-formatters [_ | ||
^vector? formatters-strategies | ||
^map? third-party-indent-specs] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a default for third-party-indent-specs
in cljfmt/new
and cider/new
. Then we can remove the references to third-party-indent-specs
.
Consumers should overwrite the entire member if they want to change the specs. (which is how other members should work anyway). wdyt?
(assoc :strategies (conj formatters-strategies | ||
strategies/files-with-a-namespace | ||
strategies/exclude-edn))) | ||
(when (strategies/refactor-nrepl-available?) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we solve this with override
-configuration? e.g. adding the formatter when nrepl is available.
(defn format-and-lint-branch! | ||
"Note that files that are not completely staged will not be affected. | ||
|
||
You can override that with `:blacklist []`." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docstring is correctly reflects the intended behavior, however not linting unstaged files is suboptimal.
After all, linting things is safe, so there's no reason to omit it (and it tends to be surprising; has bit me in the past).
Should be easy to fix.
:in-background? in-background?))) | ||
|
||
(defn lint-branch! [& {:keys [target-branch in-background? reporter] | ||
(defn lint-branch! [& {:keys [target-branch in-background? reporter overrides] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first thing that comes to mind is that the config should be a single map, so that it can become data.
- data (a single hashmap) is simpler than code (a more intrincate invocation consisting of multiple arguments)
- a single hashmap can be (more) easily a resource, a piece of Lein config, etc.
- this is important, as one will want to share config across projects.
- I envision this being accomplished by creating a single dep, containing a .edn as a resource. Zero config or
require
s to be done for consumers: we just discover the presence of such a config file.
- I envision this being accomplished by creating a single dep, containing a .edn as a resource. Zero config or
- this is important, as one will want to share config across projects.
- Hashmaps can be (deep) merged
- Not hard to imagine that people can want a merge of f-s defaults <-> workplace defaults <-> personal defaults.
It's also good to emphasize the notion of overrides as:
- a thing you should be aware of
- if I can pass
:linters
separately, I can be unaware of the existence a deep-merged overrides system - unawareness -> confusion, surprises, etc
- if I can pass
- the sole intended API
- More APIs -> more complexity (surface area for bugs)
[& {:keys [target-branch in-background? reporter formatters blacklist overrides] | ||
:or {target-branch "master" | ||
in-background? (not (System/getenv "CI")) | ||
reporter default-reporter}}] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could :pre that no :linters, :formatters etc are passed as an argument (b/c deprecation)
processors | ||
reporter | ||
in-background?]}] | ||
(speced/defn format! [& {:keys [^vector? strategies |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could assoc the strategies in format! (they are impl detail anyway)
See my comment beginning with The first thing that comes to mind [...]
(assert (apply distinct? ids) | ||
"Members should have unique ids")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will check what can be done. At the very least a pr-str ids
is due
(try | ||
(sut/apply-overrides members overrides) | ||
(catch AssertionError _ | ||
::EXCEPTION)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an are
test case that will expect this ::EXCEPTION
, so these aren't omitted
(that's part of why I put these in caps - to make it more immediately visible that something is both declared and consumed)
Let's try the alternative approach that is in the oven 👀 |
Brief
Implements #134 (comment)
Starting from this PR,
:overrides
becomes the primary API for customizing things: as a consumer, one should:git-status-formatter
,branch-formatter
,project-formatter
:overrides
to those if wanting to tweak something....and should not:
core/format!
directlyTODO
git-status-formatter
,branch-formatter
,project-formatter
all deserve some test coverage.git-status-formatter
,branch-formatter
,project-formatter
impl
sub-nses forgit-status-formatter
,branch-formatter
,project-formatter
format-and-lint!
/lint!
speced/defn default-formatters
are certainly not publiccheck!
QA plan
git-status-formatter
,branch-formatter
,project-formatter
all keep workingAuthor checklist
Reviewer checklist