Run these before opening a pull request. They are the same checks CI runs:
./gradlew ktlintFormat # fix code style
./gradlew ktlintCheck lintDebug lintRelease # code style + Android Lint
./gradlew testDebugUnitTest # unit tests
./gradlew apiCheck # public API unchanged (see below)
./gradlew assembleDebug assembleRelease publishToMavenLocal
./gradlew :sample:assembleQa # minified sample, catches R8 problemsLint warnings fail the build, so fix them rather than ignoring them. Dependency-version warnings are turned off because Dependabot handles updates.
The build needs JDK 17. Gradle picks up an installed JDK 17 for its daemon (see gradle/gradle-daemon-jvm.properties) and downloads one only if none is found.
Each published module records its public API in <module>/api/<module>.api. ./gradlew apiCheck (run by CI, the release workflow and ./gradlew check) fails when the compiled release classes no longer match that file.
- Adding API (a new public class, function or property) is fine in a feature release. Run
./gradlew apiDumpand commit the updated.apifiles with your change. - Removing or changing API (renaming, changing a signature, making something
internal) breaks apps built against the previous version. That needs a major release and aBREAKING:changelog entry, so avoid it where an addition would do. Adding a parameter to an existing public function or constructor changes its JVM signature too, even with a default value: keep the old signature as an overload (it can be@Deprecated(level = DeprecationLevel.HIDDEN)). - Mark anything users shouldn't call
internal, so it stays out of the dump.
Review .api diffs like code: every line is a promise to library users.
- Branch from
mainand open a PR againstmain. - Add a line under [Unreleased] in
CHANGELOG.md, under### Added,### Changed,### Fixedor### Removed, and writeBREAKING:in front of anything that breaks existing code. Theautorelease type uses these headings. Use theskip-changeloglabel for changes users won't notice, like CI or docs. - CI must pass: Lint, Build and test and Changelog.
- A code owner (see
.github/CODEOWNERS) must approve. - Merged PRs are added to the Next release milestone automatically.
DevDeck uses Semantic Versioning with AndroidX-style pre-releases: 1.2.0 for stable releases, and 1.2.0-alpha01, 1.2.0-beta01, 1.2.0-rc01 before that (two-digit counters, alpha → beta → rc → stable). The version lives in one place: VERSION_NAME in gradle.properties, and the release workflow rejects any other format.
-
Run the Bump version workflow (Actions tab → Bump version) and pick the release type:
Release type Example Use for fix1.0.0 → 1.0.1 Bug fixes only feature1.0.0 → 1.1.0 New features or behaviour changes major0.x → 1.0.0, then 1.x → 2.0.0 The first stable release, and later breaking changes: removed or renamed public API, changed defaults alpha1.1.0 → 1.2.0-alpha01, then → 1.2.0-alpha02 Early previews; APIs may still change beta1.2.0-alpha03 → 1.2.0-beta01 Feature complete; fixes only from here rc1.2.0-beta02 → 1.2.0-rc01 Release candidate; ships unchanged unless a blocker turns up stable1.2.0-rc01 → 1.2.0 Drops the pre-release suffix auto(default)— Picks one from the [Unreleased]entries inCHANGELOG.md:### Removedor the wordBREAKING→ major;### Added/### Changed→ feature; only### Fixed→ fix. While on 0.x, breaking changes stay a feature release, so 1.0.0 only happens when you choosemajorIt updates
VERSION_NAME, moves the Unreleased changelog entries under the new version, and opens a Release vX.Y.Z pull request. -
Merge that pull request. The Release workflow then:
- builds and tests,
- signs the four libraries and publishes them to Maven Central as
io.github.appshipkit:<module>:<version>(they appear on central.sonatype.com within about 30 minutes), - creates the
vX.Y.Ztag and a GitHub release with the changelog notes, marked as a pre-release for alpha, beta and rc versions, - closes the
vX.Y.Zmilestone (stable releases only).
Publishing an older release: to put an already tagged version on Maven Central (for example one released before DevDeck moved there), create a branch from its tag, add the Maven Central setup, and run the Publish to Maven Central workflow (Actions tab) with that branch. The tag itself stays as it was.
You can also bump locally with scripts/bump-version.sh <fix|feature|major|alpha|beta|rc|stable|auto|version> and open the PR yourself. ./gradlew publishToMavenLocal installs the libraries in ~/.m2 to try them in another project.
Do this once after creating the GitHub repository:
- Settings → Branches → Add branch protection rule for
main:- Require a pull request before merging, with Require review from Code Owners.
- Require status checks to pass:
Lint,Build and test,Changelog. - Require branches to be up to date before merging.
- Settings → Actions → General → Workflow permissions: select Read and write permissions and tick Allow GitHub Actions to create and approve pull requests (needed by Bump version).
- Optional:
RELEASE_TOKENsecret. Pull requests opened with the default Actions token don't trigger CI, so the release PR's required checks won't run. Add a fine-grained personal access token with Contents and Pull requests write access as a repository secret namedRELEASE_TOKEN, and Bump version will use it. Without it, re-run the checks by pushing an empty commit to the release branch, or merge as an admin. - Labels and milestone: run the Set up repository workflow once (Actions tab). It creates the
bug,enhancement,dependenciesandskip-changeloglabels used by the templates, Dependabot and CI, plus the Next release milestone. - Maven Central publishing. The release workflow needs these, set up once by an admin of the appshipkit organization:
- Sign in to the Central Portal with GitHub, then Namespaces → Add namespace
io.github.appshipkit. It shows a verification key; create a public repository with that exact name in the appshipkit organization, press Verify, then delete the repository. - Account → Generate user token. Save the token's username and password.
- Create a signing key:
gpg --full-generate-key(RSA 4096), publish the public key withgpg --keyserver keyserver.ubuntu.com --send-keys <KEY_ID>, and export the private key withgpg --armor --export-secret-keys <KEY_ID>. - Add four repository secrets (Settings → Secrets and variables → Actions):
MAVEN_CENTRAL_USERNAMEandMAVEN_CENTRAL_PASSWORD(the token),SIGNING_KEY(the exported private key, including the BEGIN/END lines) andSIGNING_KEY_PASSWORD.
- Sign in to the Central Portal with GitHub, then Namespaces → Add namespace