From bf4bf537eb1203ac25048cd42e7cc5332be2f259 Mon Sep 17 00:00:00 2001 From: Antal Monori Date: Sun, 23 Aug 2026 09:46:05 +0100 Subject: [PATCH] Improve talk links and code styling --- _layouts/talk.html | 2 +- ...22-where-should-gradle-build-logic-live.md | 22 ++++-- assets/css/style.css | 78 ++++++++++++++++--- 3 files changed, 84 insertions(+), 18 deletions(-) diff --git a/_layouts/talk.html b/_layouts/talk.html index 48abf9e..0e31e66 100644 --- a/_layouts/talk.html +++ b/_layouts/talk.html @@ -20,7 +20,7 @@ {% endif %} {% for post in page.relevant_posts %} -

Read {{ post.title }} →

+

Read relevant blog post

{% endfor %} {{ content }} diff --git a/_posts/2026-08-22-where-should-gradle-build-logic-live.md b/_posts/2026-08-22-where-should-gradle-build-logic-live.md index 741cb30..16a6706 100644 --- a/_posts/2026-08-22-where-should-gradle-build-logic-live.md +++ b/_posts/2026-08-22-where-should-gradle-build-logic-live.md @@ -77,7 +77,7 @@ buildSrc/ The name of the file exposes the plugin as `sample.android.library`, which can then can already be applied to your project build scripts using `plugins { id("sample.android.library") }` -See this in [[Step 1] Extract build logic into buildSrc /w precompiled scripts](https://github.com/anthonymonori/sample-gradle-project/pull/5). +See this in [[Step 1] Extract build logic into buildSrc /w precompiled scripts](https://github.com/anthonymonori/sample-gradle-project/commit/ea9ca7606aaeff487ad91fb6d6330cdeb7438b9b). ## Is `buildSrc` the right place? @@ -98,7 +98,7 @@ We can turn the `buildSrc` into a regular, explicitly included Gradle build proj Composite builds are useful for more than build logic, but sharing plugins is one of their primary use cases. Read more about [composite builds](https://docs.gradle.org/current/userguide/composite_builds.html). -See this in [[Step 2] Move from buildSrc to build-logic /w precompiled scripts](https://github.com/anthonymonori/sample-gradle-project/pull/4). +See this in [[Step 2] Move from buildSrc to build-logic /w precompiled scripts](https://github.com/anthonymonori/sample-gradle-project/commit/a2dbee2ae7c62b8d035c88245e6be3d367c8e8ae). If you have a small project and want the simplest possible setup, `buildSrc` remains a reasonable choice. If the build logic is growing, has dedicated ownership, or needs a clearer classpath and project boundary, an included build is likely a better fit. @@ -108,7 +108,7 @@ Our `sample.android.library.gradle.kts` is already a plugin. Gradle generates a Defining a [binary plugin](https://docs.gradle.org/current/userguide/implementing_gradle_plugins_binary.html#header) gives the implementation a clearer structure. We can split responsibilities across regular classes, use explicit types, isolate optional features, and test individual behaviours more easily — just like with our product source code. It also gives us greater control over how the plugin reacts to other plugins and which parts of its implementation become public. -See this in [[Step 3] Replace precompiled scripts with binary convention plugins](https://github.com/anthonymonori/sample-gradle-project/pull/3). +See this in [[Step 3] Replace precompiled scripts with binary convention plugins](https://github.com/anthonymonori/sample-gradle-project/commit/dc96b4de27d5e51c06110da3c7dfd807e28914dc). This does not change the experience of the consuming module. It still applies the same convention plugin by ID. We are only changing how that convention is implemented behind the boundary. @@ -116,7 +116,7 @@ This does not change the experience of the consuming module. It still applies th So far, we have focused on module configuration. However, a large amount of important build logic also lives in `settings.gradle.kts`. Settings may define repository policy, plugin resolution, build-cache configuration, feature previews, project discovery, and included builds. If this logic needs to be shared across multiple repositories, we can place it behind a settings plugin in exactly the same spirit as our project conventions. -See this in [[Step 4] Extract settings logic into a binary convention plugin](https://github.com/anthonymonori/sample-gradle-project/pull/2). +See this in [[Step 4] Extract settings logic into a binary convention plugin](https://github.com/anthonymonori/sample-gradle-project/commit/c05d905d77ac12cf1d317a9b7bec6f8319594696). ## What happens when modules need different capabilities? @@ -164,7 +164,7 @@ sample { The build logic can then apply the correct plugin and dependency configuration. Later, if we later make KSP the default, we can change that convention in one place. Modules that do not require a special override remain untouched. -See this in [[Step 5] Introduce a custom DSL for opt-in build features](https://github.com/anthonymonori/sample-gradle-project/pull/1). +See this in [[Step 5] Introduce a custom DSL for opt-in build features](https://github.com/anthonymonori/sample-gradle-project/commit/2a97f1e6a325de7a2d9c551e1132852573c13e88). *In the next post, I’ll go into more detail about how to define a custom Gradle DSL, model its configuration lazily, and turn those declarations into plugin behaviour.* @@ -180,7 +180,17 @@ As the conventions become more complex, binary plugins let us organise the imple Finally, when modules need to select higher-level capabilities, a small custom DSL can become the public interface to that build logic. You do not necessarily need to reach the final step. Each abstraction should earn its place by removing a real source of repetition, inconsistency, or migration cost. -You can explore the complete progression in the [sample Gradle project](https://github.com/anthonymonori/sample-gradle-project), with each step preserved as a pull request. +You can explore the complete progression in the [sample Gradle project](https://github.com/anthonymonori/sample-gradle-project), with each step preserved as a commit. + +## Watch the talk + +This article accompanies my talk, *Scaling Your Build Logic*, presented at Londroid. + +
+ +
+ +[View the talk page and slides →](/talks/scaling-your-build-logic) --- diff --git a/assets/css/style.css b/assets/css/style.css index fc0bb23..087e077 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -5,6 +5,11 @@ --body-bg: #fff; --primary-font-color: #000; --border-color: #dadada; + --link-color: #0969da; + --link-hover-color: #0550ae; + --inline-code-bg: #eff1f3; + --inline-code-border: #d8dee4; + --code-block-border: #3f4347; } [data-theme="dark"] { @@ -13,6 +18,11 @@ --body-bg: #10171e; --primary-font-color: #bfbfbf; --border-color: #6a6a6a; + --link-color: #79b8ff; + --link-hover-color: #a8d1ff; + --inline-code-bg: #252f3a; + --inline-code-border: #46515c; + --code-block-border: #59636e; } body{ @@ -69,7 +79,7 @@ body{ background: var(--bg-hover-color); } -.post-list .post-title{width: 80%; color: var(--primary-font-color); font-weight: 600;} +.post-list .post-title{width: 80%; font-weight: 600;} .post-list .post-date{width: 20%; text-align: right;} .post-header{ @@ -116,8 +126,8 @@ body{ border:1px dashed var(--border-color); } -.navigation .prev{width: 45%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--primary-font-color); font-weight: 600; padding: 5px 10px;} -.navigation .next{width: 45%; color: var(--primary-font-color); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-weight: 600; text-align: right; padding: 5px 10px;} +.navigation .prev{width: 45%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-weight: 600; padding: 5px 10px;} +.navigation .next{width: 45%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-weight: 600; text-align: right; padding: 5px 10px;} .pagination{ width: 100%; @@ -130,15 +140,15 @@ body{ margin-bottom: 5px; background:var(--bg-color); } -.pagination .prev{color: var(--primary-font-color); font-weight: 600;} -.pagination .next{color: var(--primary-font-color); font-weight: 600; text-align: right;} +.pagination .prev{font-weight: 600;} +.pagination .next{font-weight: 600; text-align: right;} .blog-post-content{ width: 100%; font-size: 18px; } -.post-tag{background: var(--bg-color); color:var(--primary-font-color); padding: 5px 10px;} +.post-tag{background: var(--bg-color); padding: 5px 10px;} .profile{ width: 100%; @@ -168,11 +178,57 @@ body{ .text-right{text-align: right;} .w-100{width: 100%!important;} -a:hover{text-decoration: none;} -a{color: var(--primary-font-color); text-decoration: none;} +a{ + color: var(--link-color); + text-decoration: underline; + text-decoration-thickness: 1px; + text-underline-offset: 0.16em; +} +a:hover{ + color: var(--link-hover-color); + text-decoration-thickness: 2px; +} +.nav-links a, +.nav-links a:hover{ + color: var(--primary-font-color); + text-decoration: none; +} img{max-width: 100%;} figure{margin:0; padding: 15px;} -pre{font-size: 14px; max-width: 90vw; overflow: auto;} +pre, +code{ + font-family: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + font-variant-ligatures: none; +} +.blog-post-content :not(pre) > code{ + padding: 0.1em 0.32em; + background: var(--inline-code-bg); + border: 1px solid var(--inline-code-border); + border-radius: 4px; + font-size: 0.88em; +} +pre{ + max-width: 90vw; + margin: 1.25em 0; + padding: 1rem 1.15rem; + overflow: auto; + font-size: 14px; + line-height: 1.55; + tab-size: 4; +} +.highlight{ + margin: 1.25em 0; + overflow: hidden; + border: 1px solid var(--code-block-border); + border-radius: 7px; +} +.highlight pre{ + max-width: none; + margin: 0; +} +.highlight code{ + font-size: inherit; +} .social-icon{height: 24px;} @media (min-width: 1200px){ @@ -210,5 +266,5 @@ pre{font-size: 14px; max-width: 90vw; overflow: auto;} .section-subheader .post-title {font-size: 1em; opacity: 0.7;} .video-container {position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; margin: 1.5em 0;} -.video-container iframe {position: absolute; top: 0; left: 0; width: 100%; height: 100%;} -.talk-header {font-size: 1.1em; margin-bottom: 1.5em;} \ No newline at end of file +.video-container iframe {position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;} +.talk-header {font-size: 1.1em; margin-bottom: 1.5em;}