{"id":34623734,"url":"https://github.com/block/artifact-swap","last_synced_at":"2026-01-28T17:15:55.461Z","repository":{"id":319157026,"uuid":"1077114460","full_name":"block/artifact-swap","owner":"block","description":"A system for speeding up Gradle builds and IDE syncs by swapping artifacts to be used instead of gradle projects","archived":false,"fork":false,"pushed_at":"2026-01-13T17:47:05.000Z","size":695,"stargazers_count":7,"open_issues_count":12,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-13T18:46:36.083Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/block.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":"GOVERNANCE.md","roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-10-15T19:50:35.000Z","updated_at":"2026-01-13T17:47:09.000Z","dependencies_parsed_at":"2025-10-18T08:34:10.240Z","dependency_job_id":null,"html_url":"https://github.com/block/artifact-swap","commit_stats":null,"previous_names":["block/artifact-swap"],"tags_count":9,"template":false,"template_full_name":"block/oss-project-template","purl":"pkg:github/block/artifact-swap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/block%2Fartifact-swap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/block%2Fartifact-swap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/block%2Fartifact-swap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/block%2Fartifact-swap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/block","download_url":"https://codeload.github.com/block/artifact-swap/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/block%2Fartifact-swap/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28513973,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T13:38:16.342Z","status":"ssl_error","status_checked_at":"2026-01-17T13:37:44.060Z","response_time":85,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-24T15:43:14.391Z","updated_at":"2026-01-28T17:15:55.453Z","avatar_url":"https://github.com/block.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Artifact Swap\n## Overview\n\nArtifact Swap is a Gradle and IntelliJ plugin that dramatically accelerates IDE sync times for large Gradle builds. It works by swapping local Gradle projects with eagerly fetched, pre-compiled artifacts when appropriate, minimizing the number of projects Gradle needs to configure. This can result in a 50% reduction in sync times for large projects. See our [blog post][shrinking-elephants] and [this Droidcon NYC talk][airbnb-droidcon-talk] for more details.\n\n## How It Works\nArtifact Swap operates through three main components:\n\n1. **Gradle Plugin**: Analyzes your project structure, determines which modules to include based on local changes and dependencies, and configures Gradle to use artifacts instead of project references\n2. **CLI Tool**: Downloads artifacts from your artifact repository and manages a local Bill of Materials (BOM) that tracks artifact versions\n3. **IDE Plugin**: Helps navigate between project source code and the swapped artifacts\n\n## Prerequisites\n- A Gradle build using [Spotlight][spotlight] and at least Gradle 8.12\n- Java 17 or higher for running the CLI tool\n- [Spotlight IDE Plugin][spotlight-ide-plugin]\n\n## Getting Started\n### 1. Apply the Plugin\nIn your `settings.gradle(.kts)`, apply the Artifact Swap settings plugin:\n\n```kotlin\npluginManagement {\n  repositories {\n    mavenCentral()\n  }\n\n  plugins {\n    id(\"xyz.block.artifactswap.settings\") version \"\u003clatest\u003e\"\n  }\n}\n\nplugins {\n  id(\"xyz.block.artifactswap.settings\")\n}\n```\n\n### 2. Configure Required Properties\nCreate or update `gradle.properties` in your project root with the required configuration:\n\n```properties\n# Primary repository name in your artifact management system\nartifactswap.primaryRepositoryName=my-company-artifacts\n\n# Maven group ID for your internal artifacts\nartifactswap.primaryArtifactsMavenGroup=com.mycompany.artifactswap.artifacts\n\n# Git branch name where BOM versions are published\nartifactswap.bomSourceBranchName=origin/artifact-swap-green-main\n\n# Base URL for your Artifactory instance\nartifactswap.artifactoryBaseUrl=https://artifactory.mycompany.com\n\n# Token file name for Artifactory authentication (used in CI)\nartifactswap.artifactoryPublisherTokenFileName=artifactory-token.txt\n```\n\n### 3. Optional: Configure the Extension\nYou can programmatically control Artifact Swap behavior in `settings.gradle(.kts)`:\n\n```kotlin\nartifactSwap {\n  // Enable/disable artifact swap\n  enabled(true)\n\n  // Or use a provider for dynamic configuration\n  enabled(providers.gradleProperty(\"artifactswap.enabled\").map { it.toBoolean() })\n}\n```\n\n### 4. Install the CLI Tool\nThe CLI tool manages artifact downloads and BOM versions. Download and install it:\n\n#### Option A: From Published Release\n```bash\n# Download the CLI distribution\nVERSION=\"\u003clatest\u003e\"\ncurl -L \"https://repo.maven.apache.org/maven2/xyz/block/artifactswap/cli/$VERSION/cli-$VERSION.zip\" -o artifactswap.zip\n\n# Extract to your tools directory\nmkdir -p tools/artifactswap\nunzip artifactswap.zip -d tools/artifactswap\n```\n\n#### Option B: Build From Source\n```bash\n# Clone and build\ngit clone https://github.com/block/artifact-swap.git\ncd artifact-swap\n./gradlew :cli:publishToMavenLocal\n\n# Extract from maven local\nVERSION=$(grep \"^version=\" gradle.properties | cut -d'=' -f2)\ncd ~/.m2/repository/xyz/block/artifactswap/cli/$VERSION\nunzip cli-$VERSION.zip -d ~/Development/your-project/tools/artifactswap\n```\n\n#### Create a Wrapper Script\nCreate a script at `scripts/artifact-swap/download-artifacts.sh`:\n\n```bash\n#!/bin/bash\nset -o errexit\nset -o pipefail\nset -o nounset\n\ngit_root=$(git rev-parse --show-toplevel)\ntools_root=\"$git_root/tools\"\nbranch=artifact-swap-green-main  # Your BOM branch name\n\n# Attempt to fetch BOM branch\nif ! git fetch origin $branch --quiet 2\u003e/dev/null; then\n  git update-ref -d refs/remotes/origin/$branch 2\u003e/dev/null || true\n  git fetch origin $branch --quiet 2\u003e/dev/null || true\nfi\n\n# Ensure the reference exists after fetch\nif ! git show-ref --verify --quiet refs/remotes/origin/$branch; then\n  git update-ref refs/remotes/origin/$branch FETCH_HEAD\nfi\n\necho \"Syncing artifacts for Artifact Swap\"\n\"$tools_root/artifactswap/artifactswap-$VERSION/bin/artifactswap\" download-artifacts \"$@\"\n```\n\nMake it executable:\n\n```bash\nchmod +x scripts/artifact-swap/download-artifacts.sh\n```\n\n### 5. Set Up Git Hooks\nTo automatically download artifacts when switching branches, configure Git hooks:\n\n```bash\n# In your project root\ncat \u003e .git/hooks/post-checkout \u003c\u003c 'EOF'\n#!/bin/bash\n./scripts/artifact-swap/download-artifacts.sh \u003e /dev/null 2\u003e\u00261 \u0026 disown\nEOF\n# Or just add the above command to an existing post-checkout hook\n\nchmod +x .git/hooks/post-checkout\n```\n\n## Usage\n### Controlling Which Modules Are Included\nUse the [Spotlight IDE Plugin][spotlight-ide-plugin] to choose the projects you want to load in the IDE.\n\nArtifact Swap automatically determines which additional modules to include based on:\n\n1. **Git Changes**: Modules that have changes (both committed or not) compared to the branch specified by the `artifactswap.bomSourceBranchName` property\n2. **Missing artifacts**: Modules without available published artifacts or ones that have not been downloaded\n3. **Always included modules**: Some projects cannot be swapped due to various limitations and can be listed in `gradle/artifact-swap-always-keep.txt`\n\nOnly projects that are transitive dependencies of your requested modules are analyzed for inclusion based on the additional critera above.\n\n### Manual Artifact Download\nDownload artifacts for the current branch:\n\n```bash\n./scripts/artifact-swap/download-artifacts.sh --logging debug\n```\n\n\n### Disabling Artifact Swap\nDisable via `gradle.properties`:\n\n```properties\nartifactswap.enabled=false\n```\n\n## How the BOM (Bill of Materials) Works\nArtifact Swap uses a BOM to track which version of each module should be used:\n\n1. **BOM Generation**: Your CI pipeline publishes a BOM file to a specific Git branch (`artifact-swap-green-main`) containing module versions\n2. **BOM Resolution**: The plugin finds the most recent commit on that branch that's also in your current branch's history\n3. **Artifact Download**: The CLI downloads all artifacts for that BOM version from Artifactory to Maven Local\n4. **Dependency Resolution**: Gradle resolves swapped dependencies from Maven Local\n\n## CI Publishing Configuration\n### How It Works\n1. **Hashing**: The `hashing` command computes content hashes for all modules to create deterministic version identifiers\n2. **Task Finding**: The `task-finder` command analyzes the build to determine which publish tasks are available\n3. **Artifact Checking**: The `artifact-checker` command queries Artifactory to filter out tasks for artifacts that already exist\n4. **Task Running**: The `task-runner` command executes only the necessary publish tasks\n5. **BOM Publishing**: The `bom-publisher` command creates and publishes a BOM file mapping each module to its content-based version\n6. **Branch Update**: The BOM tracking branch (e.g., `artifact-swap-green-main`) is updated to point to the current commit, allowing developers to discover the latest available BOM\n\nTo enable Artifact Swap in your CI pipeline, you need to set up two separate publishing steps: one for artifacts and one for the BOM.\n\n### Prerequisites\n#### 1. Apply the Publish Plugin\nThe publish plugin configures Maven publishing for your modules. Choose one of these options:\n\n**Option A: Auto-apply via Settings Plugin (Recommended)**\n\nEnable the `artifactswap.publishingEnabled` property in `gradle.properties` and the settings plugin will automatically apply the publish plugin to all library projects:\n\n```properties\nartifactswap.publishingEnabled=true\n```\n\nThe plugin is automatically applied to projects with the `java`, `java-library`, `org.jetbrains.kotlin.jvm`, or `com.android.library` plugins.\n\n\u003e [!IMPORTANT]\n\u003e All your build plugins must be loaded in the settings classpath for this to work\n\n**Option B: Manual Application via Build Logic**\n\nIf you prefer more control, apply the publish plugin manually through your convention plugins (in `build-logic/` or similar):\n\n```kotlin\n// build-logic build.gradle(.kts)\ndependencies {\n  implementation(\"xyz.block.artifactswap:gradle-publish-plugin:\u003clatest\u003e\")\n}\n```\n\n```kotlin\n// Your build-logic library plugin(s)\nclass MyLibraryPlugin : Plugin\u003cProject\u003e {\n  override fun apply(target: Project) = target.run {\n    // ...\n    pluginManager.apply(ArtifactSwapProjectPublishPlugin::class.java)\n  }\n}\n```\n\nThis approach allows you to selectively apply publishing to specific modules or customize the configuration. It also may help in situations where you have classpath issues in your build that prevent the auto-apply from working.\n\n#### 2. Configure Publishing Properties\n\nAdd these properties to your `gradle.properties`:\n\n```properties\n# Artifact repository URL for publishing\nartifactswap.artifactRepo.url=https://artifactory.mycompany.com/artifactory/my-repo\n\n# Credentials for publishing (typically set via environment variables in CI)\n# artifactswap.artifactRepo.username=publisher\n# artifactswap.artifactRepo.password=secret\n```\n\n**Note**: Credentials can also be provided via a token file. Set the `SECRETS_PATH` environment variable to a directory containing the token file specified by `artifactswap.artifactoryPublisherTokenFileName` (defaults to `artifactory-token.txt`).\n\n### Step 1: Publishing Artifacts\nThe artifact publishing process uses the CLI tool to intelligently publish only changed modules. This should be run in your main branch builds:\n\n```bash\n#!/usr/bin/env bash\nset -o errexit\nset -o pipefail\nset -o nounset\n\n# Allocate memory to prevent OOM crashes\nexport ARTIFACTSWAP_TOOL_OPTS=\"-Xmx3072M\"\n# Configure your CI pipeline to save this artifact for use in the BOM publishing stage\nexport ARTIFACTSWAP_HASHING_FILE=artifactswapHashes/artifactswapHashing.out\nexport ARTIFACTSWAP_GRADLE_MAX_MEMORY=17408\n\n# 1. Hash all files to determine which modules have changed\necho \"===== Hashing Files =====\"\ntools/artifactswap/artifactswap hashing \\\n  --logging debug \\\n  --hashing-output-file \"${ARTIFACTSWAP_HASHING_FILE}\" \\\n  --gradle-max-memory ${ARTIFACTSWAP_GRADLE_MAX_MEMORY} \\\n  --gradle-jvm-args \"-XX:MaxMetaspaceSize=1g\" \\\n  --log-gradle\n\n# 2. Find the publish tasks that need to run\necho \"===== Finding Tasks to Publish =====\"\ntools/artifactswap/artifactswap task-finder \\\n  --logging debug \\\n  --gradle-max-memory ${ARTIFACTSWAP_GRADLE_MAX_MEMORY} \\\n  --gradle-args \"-Partifactswap.publishingEnabled=true -Partifactswap.artifactVersionFile=${ARTIFACTSWAP_HASHING_FILE}\" \\\n  --gradle-jvm-args \"-XX:MaxMetaspaceSize=1g\" \\\n  --task-list-output-directory \"taskOutputs\" \\\n  --task publishToArtifactSwapRepository \\\n  --log-gradle \\\n  --output-mode \"SINGLE_TASK_LIST\"\n\n# 3. Check which artifacts already exist in Artifactory\necho \"===== Checking Artifacts =====\"\ntools/artifactswap/artifactswap artifact-checker \\\n  --logging debug \\\n  --hash-file \"${ARTIFACTSWAP_HASHING_FILE}\" \\\n  --input-file \"taskOutputs/task-output.out\" \\\n  --output-file \"taskOutputs/task-output-filtered.out\"\n\n# 4. Publish only the artifacts that don't already exist\necho \"===== Publishing Artifacts =====\"\ntools/artifactswap/artifactswap task-runner \\\n  --logging debug \\\n  --gradle-max-memory ${ARTIFACTSWAP_GRADLE_MAX_MEMORY} \\\n  --gradle-args \"-Partifactswap.publishingEnabled=true -Partifactswap.artifactVersionFile=${ARTIFACTSWAP_HASHING_FILE}\" \\\n  --gradle-jvm-args \"-XX:MaxMetaspaceSize=1g\" \\\n  --task-list-file \"taskOutputs/task-output-filtered.out\" \\\n  --log-gradle\n```\n\n### Step 2: Publishing the BOM\nAfter artifacts are published, publish the BOM to Artifactory and update the BOM tracking branch:\n\n```bash\n#!/usr/bin/env bash\nset -o errexit\nset -o pipefail\nset -o nounset\n\nexport ARTIFACTSWAP_TOOL_OPTS=\"-Xmx3072M\"\n# This file should be consumed as an artifact from the previous pipeline stage\nexport ARTIFACTSWAP_HASHING_FILE=artifactswapHashes/artifactswapHashing.out\nexport BOM_BRANCH=artifact-swap-green-main  # Your BOM branch name from gradle.properties\n\necho \"===== Publishing BOM =====\"\ntools/artifactswap/artifactswap bom-publisher \\\n  --logging debug \\\n  --bom-version \"${GIT_COMMIT}\" \\\n  --hash-file-location \"${ARTIFACTSWAP_HASHING_FILE}\"\n\necho \"===== Updating BOM Branch =====\"\n# Update the BOM tracking branch to point to the current commit\n# This allows developers to find the most recent BOM for their branch\ngit fetch origin \"${BOM_BRANCH}\" || true\ngit branch -f \"${BOM_BRANCH}\" \"${GIT_COMMIT}\"\ngit push origin \"${BOM_BRANCH}\"\n```\n\n\u003e [!TIP]\n\u003e Configure your CI pipeline to only run the BOM publishing job after all your other check tasks have completed successfully. This will prevent compilation issues from \"poisoning\" the IDE artifacts.\n\n## Contributing\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and contribution guidelines.\n\n## License\nSee [LICENSE](LICENSE) for license information.\n\n[shrinking-elephants]: https://engineering.block.xyz/blog/shrinking-elephants\n[airbnb-droidcon-talk]: https://www.droidcon.com/2023/10/06/supercharging-ide-and-sync-performance/\n[spotlight]: https://github.com/joshfriend/spotlight\n[spotlight-ide-plugin]: https://plugins.jetbrains.com/plugin/27451-spotlight\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblock%2Fartifact-swap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblock%2Fartifact-swap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblock%2Fartifact-swap/lists"}