You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CONTRIBUTING.md
+59-24Lines changed: 59 additions & 24 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -72,43 +72,78 @@ Featured has **no deprecation or migration window**. Breaking changes are made d
72
72
-**Android (Stable):** a breaking public-API change (removed/renamed symbol, changed signature) requires a `MAJOR` version bump.
73
73
-**iOS (Preview) and JVM (Preview):** public API may change in `MINOR` releases without a major bump; no migration window is provided.
74
74
75
+
## Branching Model
76
+
77
+
| Branch | Role | Merge policy |
78
+
|--------|------|--------------|
79
+
|`develop`| Integration branch — target of all PRs | Linear history only (squash or rebase merge). Enforced by branch ruleset `required_linear_history`. |
80
+
|`main`| Release branch — updated only on releases | Accepts real merge commits (`--no-ff`) pushed directly. No squash restriction. |
|`develop` → `main` at release time |**Real merge commit** (`git merge --no-ff`), pushed directly to `main` — not via a PR |
86
+
| Back-merge `main` → `develop` after release |**Squash-PR** into `develop` (bumps version to next `-SNAPSHOT`, syncs `Package.swift`) |
87
+
88
+
The real merge on release is intentional: it makes all `develop` commits ancestors of `main`, so history never diverges. Using a squash-PR for `develop` → `main` would collapse those commits and cause `main` to accumulate history that is not in `develop`'s ancestry — requiring periodic manual reconciliation (see issue #226).
89
+
75
90
## Releasing a New Version
76
91
77
-
Releases are fully automated via the [publish workflow](.github/workflows/publish.yml). A release is triggered by pushing a version tag to the repository.
92
+
Releases are driven by a four-step process. The [publish workflow](.github/workflows/publish.yml) is triggered by a version tag push.
93
+
94
+
### Step 1 — Prepare the release on `develop`
95
+
96
+
Update `gradle.properties` to the release version (remove the `-SNAPSHOT` suffix) and update `CHANGELOG.md`. Merge these changes into `develop` via a normal squash-PR.
97
+
98
+
```properties
99
+
# gradle.properties
100
+
VERSION_NAME=1.0.0
101
+
```
102
+
103
+
### Step 2 — Merge `develop` into `main` with a real merge commit
104
+
105
+
Do **not** use a squash-PR here. A squash would collapse `develop`'s commits and cause `main` to diverge from `develop`'s history, requiring periodic manual reconciliation.
78
106
79
-
### Steps to Release
107
+
```bash
108
+
git checkout main && git pull
109
+
git merge --no-ff develop -m "Release v1.0.0"
110
+
git push origin main
111
+
```
112
+
113
+
`main` has no branch ruleset restrictions — a direct push of a merge commit is allowed.
80
114
81
-
1.**Update the version** in `gradle.properties`:
82
-
```properties
83
-
VERSION_NAME=1.0.0
84
-
```
85
-
The version must follow [Semantic Versioning](https://semver.org/) (e.g., `1.0.0`, `1.1.0`, `2.0.0-rc1`).
115
+
### Step 3 — Tag `main` and push the tag
86
116
87
-
2.**Commit the version bump:**
88
-
```bash
89
-
git add gradle.properties
90
-
git commit -m "chore: release v1.0.0"
91
-
```
117
+
```bash
118
+
git tag v1.0.0
119
+
git push origin v1.0.0
120
+
```
92
121
93
-
3.**Create and push a version tag:**
94
-
```bash
95
-
git tag v1.0.0
96
-
git push origin v1.0.0
97
-
```
98
-
The tag must start with `v` followed by a semver string (e.g., `v1.0.0`, `v1.2.3-rc1`).
122
+
The tag must start with `v` followed by a semver string (e.g., `v1.0.0`, `v1.2.3-rc1`). Pushing the tag triggers the automated pipeline described below.
99
123
100
124
### What the Workflow Does
101
125
102
126
Pushing a `v*` tag triggers the following automated pipeline:
103
127
104
128
| Step | Description |
105
129
|------|-------------|
106
-
|**Publish to Maven Central**| Runs on `ubuntu-latest`; signs all artifacts with GPG and publishes them to Maven Central |
130
+
|**Publish to Maven Central**| Runs on `ubuntu-latest`; signs all artifacts with GPG and uploads the deployment bundle to Sonatype Central Portal as `USER_MANAGED` — the deployment must be promoted to release manually in the Portal UI|
107
131
|**Build XCFramework**| Runs on `macos-latest`; assembles `FeaturedCore.xcframework.zip`|
108
132
|**Create GitHub Release**| Creates a GitHub Release for the tag with auto-generated release notes and attaches the XCFramework zip |
109
-
|**Update `Package.swift`**| Computes the XCFramework checksum and commits an updated `Package.swift` back to `main`|
133
+
|**Update `Package.swift`**| Computes the XCFramework checksum and commits an updated `Package.swift` directly to `main`|
134
+
135
+
SNAPSHOT versions can be published manually via `workflow_dispatch` on the Actions tab (branch-push SNAPSHOT publishing is disabled — the Central Portal namespace does not have SNAPSHOT deployment enabled).
136
+
137
+
### Step 4 — Back-merge `main` into `develop`
138
+
139
+
After the tag is pushed and the workflow has committed the updated `Package.swift` to `main`, open a PR from `main` into `develop`. This PR should:
140
+
141
+
- Bump `VERSION_NAME` in `gradle.properties` to the next development version (e.g., `1.1.0-SNAPSHOT`).
142
+
- Include the `Package.swift` update committed by the workflow bot.
143
+
144
+
Merge this PR as a **squash merge** to keep `develop` linear.
110
145
111
-
Pushes to `main` (without a tag) publish a `-SNAPSHOT`version to Maven Central for integration testing.
146
+
This back-merge does not introduce history divergence: because Step 2 used a real merge commit, all `develop` commits are already ancestors of `main`. The back-merge PR only carries the version bump and the bot-generated `Package.swift` change — it is not "returning" lost history.
112
147
113
148
### Required GitHub Secrets
114
149
@@ -128,14 +163,14 @@ The following secrets must be configured in the repository settings under **Sett
128
163
- The tag name must be the version prefixed with `v` (e.g., tag `v1.0.0` → published version `1.0.0`)
129
164
- The tag name must match the `VERSION_NAME` in `gradle.properties` (with the `v` prefix stripped)
130
165
- Pre-release versions are supported (e.g., `v1.0.0-rc1`, `v1.0.0-beta2`)
131
-
- Development snapshots on `main`use the `-SNAPSHOT` suffix (e.g., `0.1.0-SNAPSHOT`)
166
+
- Development snapshots use the `-SNAPSHOT` suffix (e.g., `1.1.0-SNAPSHOT`) and are published manually via `workflow_dispatch`
132
167
133
168
## Submitting Changes
134
169
135
-
1. Fork the repository and create a branch from `main`.
170
+
1. Fork the repository and create a branch from `develop`.
136
171
2. Make your changes in a focused, single-purpose commit or small series of commits.
137
172
3. Ensure all tests pass and `spotlessCheck` is clean.
138
-
4. Open a pull request against `main` with a clear description of what changed and why.
173
+
4. Open a pull request against `develop` with a clear description of what changed and why.
0 commit comments