1*d9e8da70SAndroid Build Coastguard Worker# Releasing LeakCanary 2*d9e8da70SAndroid Build Coastguard Worker 3*d9e8da70SAndroid Build Coastguard Worker## Preparing the release environment 4*d9e8da70SAndroid Build Coastguard Worker 5*d9e8da70SAndroid Build Coastguard Worker### Set up your Sonatype OSSRH account 6*d9e8da70SAndroid Build Coastguard Worker 7*d9e8da70SAndroid Build Coastguard Worker* Create a [Sonatype OSSRH JIRA account](https://issues.sonatype.org/secure/Signup!default.jspa). 8*d9e8da70SAndroid Build Coastguard Worker* Create a ticket to request access to the `com.squareup.leakcanary` project. Here's an example: [OSSRH-54959](https://issues.sonatype.org/browse/OSSRH-54959). 9*d9e8da70SAndroid Build Coastguard Worker* Then ask someone with deployer role from the LeakCanary team to confirm access. 10*d9e8da70SAndroid Build Coastguard Worker 11*d9e8da70SAndroid Build Coastguard Worker### Set up your signing key 12*d9e8da70SAndroid Build Coastguard Worker 13*d9e8da70SAndroid Build Coastguard Worker```bash 14*d9e8da70SAndroid Build Coastguard Worker# Create a new key 15*d9e8da70SAndroid Build Coastguard Workergpg --gen-key 16*d9e8da70SAndroid Build Coastguard Worker# List local keys. Key id is last 8 characters 17*d9e8da70SAndroid Build Coastguard Workergpg -K 18*d9e8da70SAndroid Build Coastguard Workercd ~/.gnupg 19*d9e8da70SAndroid Build Coastguard Worker# Export key locally 20*d9e8da70SAndroid Build Coastguard Workergpg --export-secret-keys -o secring.gpg 21*d9e8da70SAndroid Build Coastguard Worker# Upload key to Ubuntu servers 22*d9e8da70SAndroid Build Coastguard Workergpg --send-keys --keyserver keyserver.ubuntu.com <KEY ID> 23*d9e8da70SAndroid Build Coastguard Worker# Confirm the key can now be found 24*d9e8da70SAndroid Build Coastguard Workergpg --recv-keys --keyserver keyserver.ubuntu.com <KEY ID> 25*d9e8da70SAndroid Build Coastguard Worker``` 26*d9e8da70SAndroid Build Coastguard Worker 27*d9e8da70SAndroid Build Coastguard Worker### Set up your home gradle.properties 28*d9e8da70SAndroid Build Coastguard Worker 29*d9e8da70SAndroid Build Coastguard WorkerAdd this to your `~/.gradle/gradle.properties`: 30*d9e8da70SAndroid Build Coastguard Worker 31*d9e8da70SAndroid Build Coastguard Worker``` 32*d9e8da70SAndroid Build Coastguard Workersigning.keyId=<KEY ID> 33*d9e8da70SAndroid Build Coastguard Workersigning.password=<KEY PASSWORD> 34*d9e8da70SAndroid Build Coastguard Workersigning.secretKeyRingFile=/Users/YOUR_USERNAME_/.gnupg/secring.gpg 35*d9e8da70SAndroid Build Coastguard WorkerSONATYPE_NEXUS_USERNAME=<SONATYPE_USERNAME> 36*d9e8da70SAndroid Build Coastguard WorkerSONATYPE_NEXUS_PASSWORD=<SONATYPE_PASSWORD> 37*d9e8da70SAndroid Build Coastguard Worker``` 38*d9e8da70SAndroid Build Coastguard Worker 39*d9e8da70SAndroid Build Coastguard Worker### Set up the Google Analytics docs key 40*d9e8da70SAndroid Build Coastguard Worker 41*d9e8da70SAndroid Build Coastguard WorkerAdd this to your `~/.bashrc`: 42*d9e8da70SAndroid Build Coastguard Worker 43*d9e8da70SAndroid Build Coastguard Worker```bash 44*d9e8da70SAndroid Build Coastguard Workerexport LEAKCANARY_GOOGLE_ANALYTICS_KEY="UA-142834539-1" 45*d9e8da70SAndroid Build Coastguard Worker``` 46*d9e8da70SAndroid Build Coastguard Worker 47*d9e8da70SAndroid Build Coastguard Worker### Set up GitHub CLI 48*d9e8da70SAndroid Build Coastguard Worker 49*d9e8da70SAndroid Build Coastguard WorkerInstall GitHub CLI 50*d9e8da70SAndroid Build Coastguard Worker 51*d9e8da70SAndroid Build Coastguard Worker```bash 52*d9e8da70SAndroid Build Coastguard Workerbrew install gh 53*d9e8da70SAndroid Build Coastguard Worker``` 54*d9e8da70SAndroid Build Coastguard Worker 55*d9e8da70SAndroid Build Coastguard WorkerInstall jq, a CLI Json processor 56*d9e8da70SAndroid Build Coastguard Worker 57*d9e8da70SAndroid Build Coastguard Worker```bash 58*d9e8da70SAndroid Build Coastguard Workerbrew install jq 59*d9e8da70SAndroid Build Coastguard Worker``` 60*d9e8da70SAndroid Build Coastguard Worker 61*d9e8da70SAndroid Build Coastguard WorkerSet up aliases for milestone management: 62*d9e8da70SAndroid Build Coastguard Worker 63*d9e8da70SAndroid Build Coastguard Worker```bash 64*d9e8da70SAndroid Build Coastguard Workergh alias set listOpenMilestones "api graphql -F owner=':owner' -F name=':repo' -f query=' 65*d9e8da70SAndroid Build Coastguard Worker query ListOpenMilestones(\$name: String\!, \$owner: String\!) { 66*d9e8da70SAndroid Build Coastguard Worker repository(owner: \$owner, name: \$name) { 67*d9e8da70SAndroid Build Coastguard Worker milestones(first: 100, states: OPEN) { 68*d9e8da70SAndroid Build Coastguard Worker nodes { 69*d9e8da70SAndroid Build Coastguard Worker title 70*d9e8da70SAndroid Build Coastguard Worker number 71*d9e8da70SAndroid Build Coastguard Worker description 72*d9e8da70SAndroid Build Coastguard Worker dueOn 73*d9e8da70SAndroid Build Coastguard Worker url 74*d9e8da70SAndroid Build Coastguard Worker state 75*d9e8da70SAndroid Build Coastguard Worker closed 76*d9e8da70SAndroid Build Coastguard Worker closedAt 77*d9e8da70SAndroid Build Coastguard Worker updatedAt 78*d9e8da70SAndroid Build Coastguard Worker } 79*d9e8da70SAndroid Build Coastguard Worker } 80*d9e8da70SAndroid Build Coastguard Worker } 81*d9e8da70SAndroid Build Coastguard Worker } 82*d9e8da70SAndroid Build Coastguard Worker'" 83*d9e8da70SAndroid Build Coastguard Worker 84*d9e8da70SAndroid Build Coastguard Workergh alias set --shell createMilestone "gh api --method POST repos/:owner/:repo/milestones --input - | jq '{ html_url: .html_url, state: .state, created_at: .created_at }'" 85*d9e8da70SAndroid Build Coastguard Worker 86*d9e8da70SAndroid Build Coastguard Workergh alias set --shell closeMilestone "echo '{\"state\": \"closed\"}' | gh api --method PATCH repos/:owner/:repo/milestones/\$1 --input - | jq '{ html_url: .html_url, state: .state, closed_at: .closed_at }'" 87*d9e8da70SAndroid Build Coastguard Worker``` 88*d9e8da70SAndroid Build Coastguard Worker 89*d9e8da70SAndroid Build Coastguard Worker### Install or update the doc generation dependencies 90*d9e8da70SAndroid Build Coastguard Worker 91*d9e8da70SAndroid Build Coastguard Worker```bash 92*d9e8da70SAndroid Build Coastguard Workerpip3 install --requirement docs/requirements.txt 93*d9e8da70SAndroid Build Coastguard Worker``` 94*d9e8da70SAndroid Build Coastguard Worker 95*d9e8da70SAndroid Build Coastguard Worker## Releasing 96*d9e8da70SAndroid Build Coastguard Worker 97*d9e8da70SAndroid Build Coastguard Worker* Create a local release branch from `main` 98*d9e8da70SAndroid Build Coastguard Worker```bash 99*d9e8da70SAndroid Build Coastguard Workergit checkout main && \ 100*d9e8da70SAndroid Build Coastguard Workergit pull && \ 101*d9e8da70SAndroid Build Coastguard Workergit checkout -b release_{{ leak_canary.next_release }} 102*d9e8da70SAndroid Build Coastguard Worker``` 103*d9e8da70SAndroid Build Coastguard Worker 104*d9e8da70SAndroid Build Coastguard Worker* Update `VERSION_NAME` in `gradle.properties` (remove `-SNAPSHOT`) 105*d9e8da70SAndroid Build Coastguard Worker```gradle 106*d9e8da70SAndroid Build Coastguard Workersed -i '' 's/VERSION_NAME={{ leak_canary.next_release }}-SNAPSHOT/VERSION_NAME={{ leak_canary.next_release }}/' gradle.properties 107*d9e8da70SAndroid Build Coastguard Worker``` 108*d9e8da70SAndroid Build Coastguard Worker 109*d9e8da70SAndroid Build Coastguard Worker* Update the current version and next version in `mkdocs.yml` 110*d9e8da70SAndroid Build Coastguard Worker```bash 111*d9e8da70SAndroid Build Coastguard Workersed -i '' 's/{{ leak_canary.next_release }}/NEXT/' mkdocs.yml 112*d9e8da70SAndroid Build Coastguard Workersed -i '' 's/{{ leak_canary.release }}/{{ leak_canary.next_release }}/' mkdocs.yml 113*d9e8da70SAndroid Build Coastguard Worker``` 114*d9e8da70SAndroid Build Coastguard Worker 115*d9e8da70SAndroid Build Coastguard Worker* Create the release 116*d9e8da70SAndroid Build Coastguard Worker```bash 117*d9e8da70SAndroid Build Coastguard Workergit commit -am "Prepare {{ leak_canary.next_release }} release" && \ 118*d9e8da70SAndroid Build Coastguard Worker./gradlew clean && \ 119*d9e8da70SAndroid Build Coastguard Worker./gradlew build && \ 120*d9e8da70SAndroid Build Coastguard Workergit tag v{{ leak_canary.next_release }} && \ 121*d9e8da70SAndroid Build Coastguard Workergit push origin v{{ leak_canary.next_release }} && \ 122*d9e8da70SAndroid Build Coastguard Worker./gradlew publish --no-daemon --no-parallel && \ 123*d9e8da70SAndroid Build Coastguard Worker./gradlew closeAndReleaseRepository && \ 124*d9e8da70SAndroid Build Coastguard Worker./gradlew shark-cli:distZip 125*d9e8da70SAndroid Build Coastguard Worker``` 126*d9e8da70SAndroid Build Coastguard Worker 127*d9e8da70SAndroid Build Coastguard WorkerNote: if anything goes wrong, you can manually drop the release at https://s01.oss.sonatype.org/ 128*d9e8da70SAndroid Build Coastguard Worker 129*d9e8da70SAndroid Build Coastguard Worker* Merge back to main 130*d9e8da70SAndroid Build Coastguard Worker```bash 131*d9e8da70SAndroid Build Coastguard Workergit checkout main && \ 132*d9e8da70SAndroid Build Coastguard Workergit pull && \ 133*d9e8da70SAndroid Build Coastguard Workergit merge --no-ff release_{{ leak_canary.next_release }} 134*d9e8da70SAndroid Build Coastguard Worker``` 135*d9e8da70SAndroid Build Coastguard Worker* Update `VERSION_NAME` in `gradle.properties` (increase version and add `-SNAPSHOT`) 136*d9e8da70SAndroid Build Coastguard Worker```gradle 137*d9e8da70SAndroid Build Coastguard Workersed -i '' 's/VERSION_NAME={{ leak_canary.next_release }}/VERSION_NAME=NEXT-SNAPSHOT/' gradle.properties 138*d9e8da70SAndroid Build Coastguard Worker``` 139*d9e8da70SAndroid Build Coastguard Worker 140*d9e8da70SAndroid Build Coastguard Worker* Generate the Dokka docs 141*d9e8da70SAndroid Build Coastguard Worker```bash 142*d9e8da70SAndroid Build Coastguard Workerrm -rf docs/api && ./gradlew siteDokka 143*d9e8da70SAndroid Build Coastguard Worker``` 144*d9e8da70SAndroid Build Coastguard Worker 145*d9e8da70SAndroid Build Coastguard Worker* Update the changelog ([commit list](https://github.com/square/leakcanary/compare/v{{ leak_canary.release }}...main)) 146*d9e8da70SAndroid Build Coastguard Worker``` 147*d9e8da70SAndroid Build Coastguard Workermate docs/changelog.md 148*d9e8da70SAndroid Build Coastguard Worker``` 149*d9e8da70SAndroid Build Coastguard Worker 150*d9e8da70SAndroid Build Coastguard Worker* Deploy the docs locally then [open the changelog](http://127.0.0.1:8000/leakcanary/changelog/) and check everything looks good 151*d9e8da70SAndroid Build Coastguard Worker```bash 152*d9e8da70SAndroid Build Coastguard Workermkdocs serve 153*d9e8da70SAndroid Build Coastguard Worker``` 154*d9e8da70SAndroid Build Coastguard Worker 155*d9e8da70SAndroid Build Coastguard Worker* Finish up the release 156*d9e8da70SAndroid Build Coastguard Worker 157*d9e8da70SAndroid Build Coastguard Worker```bash 158*d9e8da70SAndroid Build Coastguard Workergit commit -am "Prepare for next development iteration" && \ 159*d9e8da70SAndroid Build Coastguard Workergit push && \ 160*d9e8da70SAndroid Build Coastguard Workergh listOpenMilestones | jq '.data.repository.milestones.nodes[0].number' | xargs gh closeMilestone && \ 161*d9e8da70SAndroid Build Coastguard Workerecho '{ 162*d9e8da70SAndroid Build Coastguard Worker "title": "REPLACE_WITH_NEXT_VERSION_NUMBER", 163*d9e8da70SAndroid Build Coastguard Worker "state": "open", 164*d9e8da70SAndroid Build Coastguard Worker "description": "" 165*d9e8da70SAndroid Build Coastguard Worker}' | gh createMilestone && \ 166*d9e8da70SAndroid Build Coastguard Workermkdocs gh-deploy 167*d9e8da70SAndroid Build Coastguard Workergh release create v{{ leak_canary.next_release }} ./shark-cli/build/distributions/shark-cli-{{ leak_canary.next_release }}.zip --title v{{ leak_canary.next_release }} --notes 'See [Change Log](https://square.github.io/leakcanary/changelog)' 168*d9e8da70SAndroid Build Coastguard Worker``` 169*d9e8da70SAndroid Build Coastguard Worker 170*d9e8da70SAndroid Build Coastguard Worker* Open the [v{{ leak_canary.next_release }} release](https://github.com/square/leakcanary/releases/tag/v{{ leak_canary.next_release }}) to confirm everything looks good. 171*d9e8da70SAndroid Build Coastguard Worker 172*d9e8da70SAndroid Build Coastguard Worker* Upload shark-cli to [brew](https://brew.sh/): 173*d9e8da70SAndroid Build Coastguard Worker```bash 174*d9e8da70SAndroid Build Coastguard Workerbrew bump-formula-pr --url https://github.com/square/leakcanary/releases/download/v{{ leak_canary.next_release }}/shark-cli-{{ leak_canary.next_release }}.zip leakcanary-shark 175*d9e8da70SAndroid Build Coastguard Worker``` 176*d9e8da70SAndroid Build Coastguard Worker 177*d9e8da70SAndroid Build Coastguard Worker* Wait for the release to be available [on Maven Central](https://repo1.maven.org/maven2/com/squareup/leakcanary/leakcanary-android/). 178*d9e8da70SAndroid Build Coastguard Worker* Tell your friends, update all of your apps, and tweet the new release. As a nice extra touch, mention external contributions. 179