Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 47 additions & 10 deletions .buildscript/configure-signing.gradle
Original file line number Diff line number Diff line change
@@ -1,33 +1,70 @@
apply plugin: "signing"
apply plugin: "com.vanniktech.maven.publish"

if (project.hasProperty('releaseBuild')) {
println "configuring signing key"
// Find the first non-null Gradle property or environment variable
// corresponding to the given names, giving preference to Gradle properties.
String propOrEnv(String... names) {
// hasProperty, getProperty don't work when called directly in a closure;
// they need a receiver that knows about properties, like rootProject.
def p = rootProject
def result = names.findResult { p.hasProperty(it) ? p.getProperty(it) : System.getenv(it) }
if (result == null) {
logger.error("Missing gradle property or environment variable: $names")
}
return result
}

if (project.hasProperty('artifactoryRelease')) {
// Artifactory publishing (no signing required)
mavenPublish {
releaseSigningEnabled = false
targets {
uploadArchives {
releaseRepositoryUrl = propOrEnv("ARTIFACTORY_URL", "instacart_artifactory_url")
snapshotRepositoryUrl = propOrEnv("ARTIFACTORY_URL", "instacart_artifactory_url")
repositoryUsername = propOrEnv("ARTIFACTORY_USERNAME", "instacart_artifactory_username")
repositoryPassword = propOrEnv("ARTIFACTORY_PASSWORD", "instacart_artifactory_password")
}
}
}
} else if (project.hasProperty('mavenCentralRelease')) {
// Maven Central publishing (requires signing)
Properties properties = new Properties()
if (project.rootProject.file('local.properties').exists()) {
properties.load(project.rootProject.file('local.properties').newDataInputStream())
}

signing {
def signingKeyFilename = properties.signingKey

def signingKey = "${project.rootProject.file(signingKeyFilename).newDataInputStream()}"
def signingPassword = properties.signingPassword
// Support both env vars (CI) and local.properties (local dev)
def signingKeyEnv = System.getenv('SIGNING_KEY')
def signingKey
if (signingKeyEnv) {
// CI: key content directly from env var
signingKey = signingKeyEnv
} else {
// Local: read from file specified in local.properties
def signingKeyFilename = properties.signingKey
if (signingKeyFilename) {
signingKey = "${project.rootProject.file(signingKeyFilename).newDataInputStream()}"
}
}
def signingPassword = System.getenv('SIGNING_PASSWORD') ?: properties.signingPassword

useInMemoryPgpKeys(signingKey, signingPassword)
if (signingKey && signingPassword) {
useInMemoryPgpKeys(signingKey, signingPassword)
}
}

mavenPublish {
targets {
// Modify the existing uploadArchives task
uploadArchives {
repositoryUsername = properties.SONATYPE_NEXUS_USERNAME
repositoryPassword = properties.SONATYPE_NEXUS_PASSWORD
repositoryUsername = System.getenv('SONATYPE_NEXUS_USERNAME') ?: properties.SONATYPE_NEXUS_USERNAME
repositoryPassword = System.getenv('SONATYPE_NEXUS_PASSWORD') ?: properties.SONATYPE_NEXUS_PASSWORD
}
}
}
} else {
// Local development (no publishing)
mavenPublish {
releaseSigningEnabled = false
}
Expand Down
20 changes: 14 additions & 6 deletions .buildscript/upload_archives.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
#!/bin/bash

# Optional target parameter, defaults to "artifactoryRelease"
# Use "mavenCentralRelease" for Maven Central
TARGET="${1:-artifactoryRelease}"
GRADLE_ARGS="-P$TARGET"

./gradlew clean
./gradlew :formula:build -PreleaseBuild
./gradlew :formula-android:build -PreleaseBuild
./gradlew :formula-test:build -PreleaseBuild
./gradlew :formula-android-compose:build -PreleaseBuild
./gradlew :formula-lint:build -PreleaseBuild
./gradlew :formula:build $GRADLE_ARGS
./gradlew :formula-android:build $GRADLE_ARGS
./gradlew :formula-test:build $GRADLE_ARGS
./gradlew :formula-android-compose:build $GRADLE_ARGS
./gradlew :formula-lint:build $GRADLE_ARGS
./gradlew :formula-rxjava3:build $GRADLE_ARGS

# Disabling parallelism and daemon sharing is required by the vanniktech maven publish plugin.
# Without those, the artifacts will be split across multiple (invalid) staging repositories.
./gradlew uploadArchives -PreleaseBuild --no-parallel --no-daemon
./gradlew uploadArchives $GRADLE_ARGS --no-parallel --no-daemon
74 changes: 74 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Publish Library

on:
push:
branches:
- master
paths:
- 'VERSION'

jobs:
publish:
runs-on: ubuntu-latest
env:
# Artifactory
ARTIFACTORY_URL: ${{ secrets.ARTIFACTORY_URL }}
ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
# Maven Central
SONATYPE_NEXUS_USERNAME: ${{ secrets.SONATYPE_NEXUS_USERNAME }}
SONATYPE_NEXUS_PASSWORD: ${{ secrets.SONATYPE_NEXUS_PASSWORD }}
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
# Use -PmavenCentralRelease for Maven Central
GRADLE_ARGS: -PartifactoryRelease

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Configure JDK
uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: 17

- name: Read version
id: version
run: |
VERSION=$(cat VERSION | tr -d '[:space:]')
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Publishing version: $VERSION"

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3

- name: Build formula module
run: ./gradlew :formula:build $GRADLE_ARGS

- name: Build formula-android module
run: ./gradlew :formula-android:build $GRADLE_ARGS

- name: Build formula-test module
run: ./gradlew :formula-test:build $GRADLE_ARGS

- name: Build formula-android-compose module
run: ./gradlew :formula-android-compose:build $GRADLE_ARGS

- name: Build formula-lint module
run: ./gradlew :formula-lint:build $GRADLE_ARGS

- name: Build formula-rxjava3 module
run: ./gradlew :formula-rxjava3:build $GRADLE_ARGS

- name: Publish to Artifactory
run: ./gradlew uploadArchives $GRADLE_ARGS --no-parallel --no-daemon

- name: Create GitHub Release
run: |
VERSION="${{ steps.version.outputs.version }}"
gh release create "$VERSION" \
--title "$VERSION" \
--generate-notes
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
84 changes: 84 additions & 0 deletions .github/workflows/version-bump.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: Version Bump

on:
push:
branches:
- master
paths-ignore:
- 'VERSION'

jobs:
bump-version:
runs-on: ubuntu-latest
if: ${{ !contains(github.event.head_commit.message, 'Bump version to') }}

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Read current version
id: current_version
run: |
VERSION=$(cat VERSION | tr -d '[:space:]')
echo "version=$VERSION" >> $GITHUB_OUTPUT

- name: Calculate next version
id: next_version
run: |
CURRENT="${{ steps.current_version.outputs.version }}"
IFS='.' read -ra PARTS <<< "$CURRENT"
MAJOR="${PARTS[0]}"
MINOR="${PARTS[1]}"
PATCH="${PARTS[2]}"
PATCH=$((PATCH + 1))
NEXT="$MAJOR.$MINOR.$PATCH"
echo "version=$NEXT" >> $GITHUB_OUTPUT

- name: Check if PR already exists
id: check_pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
NEXT="${{ steps.next_version.outputs.version }}"
EXISTING_PR=$(gh pr list --head "bump-version/$NEXT" --json number --jq '.[0].number // empty')
if [ -n "$EXISTING_PR" ]; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "PR #$EXISTING_PR already exists for version $NEXT"
else
echo "exists=false" >> $GITHUB_OUTPUT
fi

- name: Create version bump branch and PR
if: steps.check_pr.outputs.exists == 'false'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CURRENT_VERSION: ${{ steps.current_version.outputs.version }}
NEXT_VERSION: ${{ steps.next_version.outputs.version }}
run: |
BRANCH="bump-version/$NEXT_VERSION"

git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

git checkout -b "$BRANCH"
echo "$NEXT_VERSION" > VERSION
git add VERSION
git commit -m "Bump version to $NEXT_VERSION"
git push origin "$BRANCH"

gh pr create \
--title "Bump version to $NEXT_VERSION" \
--body "$(cat <<EOF
Automated version bump from $CURRENT_VERSION to $NEXT_VERSION.

This PR was automatically created after a merge to master.

Once merged, the publish workflow will automatically release the new version to Maven Central.
EOF
)" \
--base master \
--head "$BRANCH" \
--reviewer Laimiux
45 changes: 39 additions & 6 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,49 @@
### Releasing
To release formula artifacts, make sure you have signing and configuration setup

Make sure you have `local.properties` configured
Formula supports publishing to two targets:
- **JFrog Artifactory** - Private maven repository (automatic on VERSION change)
- **Maven Central** - Public maven repository

### Automatic Publishing

When the `VERSION` file is updated on the `master` branch, the GitHub Actions workflow automatically publishes to Artifactory and creates a GitHub Release.

### Local Development

#### Artifactory
```properties
# local.properties
ARTIFACTORY_URL=
ARTIFACTORY_USERNAME=
ARTIFACTORY_PASSWORD=
```

```sh
./gradlew uploadArchives -PartifactoryRelease
```
signingKey=/path/to/maven-key.asc
signingPassword=

#### Maven Central
```properties
# local.properties
signingKey=path/to/signing-key.asc
signingPassword=your-signing-password
SONATYPE_NEXUS_USERNAME=
SONATYPE_NEXUS_PASSWORD=
```

To upload archives
```sh
.buildscript/upload_archives.sh
./gradlew uploadArchives -PmavenCentralRelease
```

### CI/CD Secrets Required

#### Artifactory
- `ARTIFACTORY_URL`
- `ARTIFACTORY_USERNAME`
- `ARTIFACTORY_PASSWORD`

#### Maven Central
- `SONATYPE_NEXUS_USERNAME`
- `SONATYPE_NEXUS_PASSWORD`
- `SIGNING_KEY` - GPG private key content
- `SIGNING_PASSWORD` - GPG key passphrase
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.8.0
5 changes: 5 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import com.android.build.api.dsl.CommonExtension
import com.android.build.api.dsl.LibraryExtension
import com.android.build.api.dsl.TestExtension

val versionName = file("VERSION").readText().trim()
allprojects {
extra["VERSION_NAME"] = versionName
}

buildscript {

repositories {
Expand Down
1 change: 0 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
GROUP=com.instacart.formula
VERSION_NAME=0.7.1

POM_DESCRIPTION=Formula

Expand Down