Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4aa8470
Add VertexAiClient interface and FakeVertexAiClient for changelog gen…
Sandesh282 Jul 6, 2026
14bee6f
Add GoogleVertexAiClient: production Vertex AI REST implementation
Sandesh282 Jul 6, 2026
8e13e92
Add GenerateChangelogs script and Bazel targets for automated changel…
Sandesh282 Jul 6, 2026
0bf63b8
Fix: remove unused kt_jvm_binary from release/BUILD.bazel load statement
Sandesh282 Jul 6, 2026
9814e60
minor fix
Sandesh282 Jul 12, 2026
a07aac8
Add unit tests for GenerateChangelogs script
Sandesh282 Jul 20, 2026
368ffc3
Fix mutable companion apiBaseUrl; add GoogleVertexAiClientTest
Sandesh282 Jul 20, 2026
c6af637
Add gh pr create arg assertions to GenerateChangelogsTest
Sandesh282 Jul 20, 2026
510cb3e
Fix ktlint blank line violations in GenerateChangelogsTest
Sandesh282 Jul 20, 2026
3161be3
Exempt VertexAiClient and FakeVertexAiClient from test file check
Sandesh282 Jul 20, 2026
e6bac62
Move FakeVertexAiClient to src/javatests; exempt VertexAiClient inter…
Sandesh282 Jul 21, 2026
6ee5859
Fix buildifier blank lines in release BUILD.bazel
Sandesh282 Jul 21, 2026
f583f28
Add FakeVertexAiClientTest to satisfy test file presence check
Sandesh282 Jul 21, 2026
8985c0e
move FakeVertexAiClient to prod source set to fix test file presence …
Sandesh282 Jul 26, 2026
f95b6d3
remove unused kt_jvm_library from javatests BUILD load statement
Sandesh282 Jul 26, 2026
66120f5
apply buildifier reformat to javatests BUILD
Sandesh282 Jul 26, 2026
aa6d3e3
add generate_changelog.yml workflow triggered on version.bzl push
Sandesh282 Jul 26, 2026
1136d88
Address reviewer comments: fix action pins, Closes→Fix/Fixes, cleanup…
Sandesh282 Jul 31, 2026
ab14f99
Add target_version input to workflow_dispatch
Sandesh282 Jul 31, 2026
cdd68bc
Wire target_version input to TARGET_VERSION env var in script step
Sandesh282 Jul 31, 2026
53c0ee2
Add set-up-android-bazel-build-environment and Bazel 6.5.0 version pin
Sandesh282 Aug 2, 2026
6ece400
add git fetch command
Sandesh282 Aug 2, 2026
302b027
Use oppia-android-automation-env (no approval gate) for changelog wor…
Sandesh282 Aug 3, 2026
4b67051
Merge upstream/develop into pr2.2 (pr2.1 landed)
Sandesh282 Aug 8, 2026
bf29ef0
Clarify secrets setup; drop automated-changelog label; delete 0.18.md…
Sandesh282 Aug 8, 2026
422044a
Update Set up Bazel step
Sandesh282 Aug 10, 2026
3eed5c3
Address review: use dedicated changelog SA, fix release branch refs t…
Sandesh282 Aug 13, 2026
de8a9af
Fix ktlint: wrap long gitMergeBase call
Sandesh282 Aug 13, 2026
cfddd58
Fix ktlint: wrap gitMergeBase args
Sandesh282 Aug 13, 2026
8efcd23
Update Bazel setup step
Sandesh282 Aug 18, 2026
6317a13
Address review: trim overinflated docstrings in generate_changelog.yml
Sandesh282 Sep 6, 2026
5dbd4e4
Add 0.18 and 0.18_alpha changelogs from upstream develop
Sandesh282 Sep 6, 2026
1a489e2
Address review
Sandesh282 Sep 7, 2026
d73380f
minor fix
Sandesh282 Sep 7, 2026
8a045e4
Fix KDoc placement: move private constants before KDoc block
Sandesh282 Sep 7, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/build_and_sign.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ jobs:
fetch-depth: 0

- name: Set up Bazel
uses: bazel-contrib/setup-bazel@8cb04a772ab4c1eb984e9c1b493a182e96c5e425
uses: bazel-contrib/setup-bazel@0.19.0
with:
bazelisk-cache: true

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/deploy_to_play_console.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ jobs:
echo "ACCESS_TOKEN=$ACCESS_TOKEN" >> "$GITHUB_ENV"

- name: Set up Bazel
uses: abhinavsingh/setup-bazel@v3
uses: bazel-contrib/setup-bazel@0.19.0
Comment thread
adhiamboperes marked this conversation as resolved.
with:
version: 6.5.0
bazelisk-cache: true

- name: Set up build environment
uses: ./.github/actions/set-up-android-bazel-build-environment
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/deploy_updated_changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ jobs:
echo "VERSION=$VERSION" >> $GITHUB_ENV

- name: Set up Bazel
uses: abhinavsingh/setup-bazel@v3
uses: bazel-contrib/setup-bazel@0.19.0
with:
version: 6.5.0
bazelisk-cache: true

- name: Set up build environment
uses: ./.github/actions/set-up-android-bazel-build-environment
Expand Down
91 changes: 91 additions & 0 deletions .github/workflows/generate_changelog.yml
Comment thread
adhiamboperes marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Triggered when a version-bump PR merges to develop (path filter: version.bzl).
# Runs GenerateChangelogs, which reads the new version, collects PRs between the
# two most recent release branches, calls Vertex AI for a summary, and opens a PR
# with the generated config/changelogs/<version>.md file.
# Can also be triggered manually via workflow_dispatch.

name: Generate Changelog

on:
push:
branches:
- develop
paths:
- 'version.bzl'
workflow_dispatch:
Comment thread
adhiamboperes marked this conversation as resolved.
inputs:
target_version:
description: >-
Version to generate changelog for (e.g. "0.17"). If empty, the version
is read from version.bzl at HEAD. Use this to regenerate a changelog
for an older release without modifying version.bzl.
required: false
default: ''

# Only one changelog generation may run at a time; cancel-in-progress: false so that
# a rapid double-push to version.bzl does not leave an inconsistent changelog branch.
concurrency:
group: generate-changelog
Comment thread
adhiamboperes marked this conversation as resolved.
cancel-in-progress: false

jobs:
generate_changelog:
name: Generate Changelog
runs-on: ubuntu-24.04
# oppia-android-automation-env (not release-env) because this workflow opens a PR
# for human review and never deploys directly. GCP_CHANGELOG_SERVICE_ACCOUNT is
# a dedicated, minimally-scoped SA separate from GCP_RELEASE_SERVICE_ACCOUNT so
# that a compromised changelog workflow cannot reach signing/Play Store resources.
environment: oppia-android-automation-env
permissions:
id-token: write
contents: write
pull-requests: write

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Configure git identity
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
Comment thread
adhiamboperes marked this conversation as resolved.

- name: Configure git remote credentials
run: |
git remote set-url origin \
https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}

- name: Authenticate to GCP via Workload Identity Federation
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
Comment thread
adhiamboperes marked this conversation as resolved.
service_account: ${{ secrets.GCP_CHANGELOG_SERVICE_ACCOUNT }}

- name: Set up Google Cloud SDK
uses: google-github-actions/setup-gcloud@v2

- name: Get and mask GCP access token
run: |
ACCESS_TOKEN="$(gcloud auth print-access-token)"
echo "::add-mask::$ACCESS_TOKEN"
echo "GCP_ACCESS_TOKEN=$ACCESS_TOKEN" >> "$GITHUB_ENV"

- name: Set up Bazel
uses: bazel-contrib/setup-bazel@0.19.0
with:
bazelisk-cache: true

- name: Set up Android + Bazel build environment
uses: ./.github/actions/set-up-android-bazel-build-environment

- name: Generate changelog and open PR
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TARGET_VERSION: ${{ inputs.target_version }}
run: |
bazel run //scripts:generate_changelogs -- \
"$(pwd)" \
"${{ secrets.GCP_PROJECT_ID }}" \
"$GCP_ACCESS_TOKEN"
4 changes: 2 additions & 2 deletions .github/workflows/update_rollout.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ jobs:
id: validate

- name: Set up Bazel
uses: abhinavsingh/setup-bazel@v3
uses: bazel-contrib/setup-bazel@0.19.0
with:
version: 6.5.0
bazelisk-cache: true

- name: Set up build environment
uses: ./.github/actions/set-up-android-bazel-build-environment
Expand Down
2 changes: 1 addition & 1 deletion config/changelogs/0.18.md
Comment thread
adhiamboperes marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Placeholder changelog for 0.18 pre-releases.
This release warns users on Android 5/5.1 of retiring support for their OS versions. It also adds full support for Android 16, and a variety of bugfixes.
1 change: 1 addition & 0 deletions config/changelogs/0.18_alpha.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This release warns users on Android 5/5.1 of retiring support for their OS versions. It also adds full support for Android 16, a variety of bugfixes and adds an alpha-specific worked examples feature to study guides.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import org.oppia.android.scripts.common.CommandExecutorImpl
import org.oppia.android.scripts.common.ScriptBackgroundCoroutineDispatcher
import java.io.File

private const val GCP_LOCATION = "us-central1"
private const val VERTEX_MODEL = "gemini-1.5-flash"

/**
* Script that automatically generates a changelog for the previous app version whenever the minor
* version is bumped in `version.bzl`, and proposes it as a pull request on `develop`.
Expand All @@ -26,32 +29,29 @@ import java.io.File
* ### Usage (called by `generate_changelog.yml` via Bazel)
* ```
* bazel run //scripts:generate_changelogs -- \
* <workspace_root> <gcp_project> <gcp_location> <vertex_model> <gcp_access_token>
* <workspace_root> <gcp_project> <gcp_access_token>
* ```
*
* ### Arguments (positional)
* 0. `workspace_root` — absolute path to the local repository root
* 1. `gcp_project` — GCP project ID that has Vertex AI enabled
* 2. `gcp_location` — Vertex AI region (e.g. "us-central1")
* 3. `vertex_model` — Vertex AI model ID (e.g. "gemini-1.5-flash")
* 4. `gcp_access_token`— GCP Bearer token for authenticating with Vertex AI
* 2. `gcp_access_token`— GCP Bearer token for authenticating with Vertex AI
*
* An optional 6th argument overrides the Vertex AI API base URL; this is used in integration
* An optional 4th argument overrides the Vertex AI API base URL; this is used in integration
* tests to route HTTP calls through a local mock server.
*/

fun main(args: Array<String>) {
require(args.size in 5..6) {
"Usage: generate_changelogs <workspace_root> <gcp_project> <gcp_location> " +
"<vertex_model> <gcp_access_token>\nGot ${args.size} argument(s): ${args.toList()}"
require(args.size in 3..4) {
"Usage: generate_changelogs <workspace_root> <gcp_project> <gcp_access_token>" +
"\nGot ${args.size} argument(s): ${args.toList()}"
}

val workspaceRoot = args[0]
val gcpProject = args[1]
val gcpLocation = args[2]
val vertexModel = args[3]
val gcpAccessToken = args[4]
val gcpAccessToken = args[2]

val overrideApiBaseUrl = if (args.size == 6) args[5] else null
val overrideApiBaseUrl = if (args.size == 4) args[3] else null

// TARGET_VERSION is set by the workflow when the user triggers workflow_dispatch with a
// specific version (e.g. "0.17"). When empty or absent, version is derived from version.bzl.
Expand All @@ -60,9 +60,11 @@ fun main(args: Array<String>) {
ScriptBackgroundCoroutineDispatcher().use { scriptBgDispatcher ->
val commandExecutor = CommandExecutorImpl(scriptBgDispatcher)
val vertexAiClient = if (overrideApiBaseUrl != null) {
GoogleVertexAiClient(gcpProject, gcpLocation, vertexModel, gcpAccessToken, overrideApiBaseUrl)
GoogleVertexAiClient(
gcpProject, GCP_LOCATION, VERTEX_MODEL, gcpAccessToken, overrideApiBaseUrl
)
} else {
GoogleVertexAiClient(gcpProject, gcpLocation, vertexModel, gcpAccessToken)
GoogleVertexAiClient(gcpProject, GCP_LOCATION, VERTEX_MODEL, gcpAccessToken)
}
generateChangelogs(
workspaceRoot = File(workspaceRoot),
Expand Down Expand Up @@ -218,12 +220,17 @@ fun parseVersionBzl(workspaceRoot: File): Pair<Int, Int> {
/**
* Computes the `fromSha..toSha` range for the changelog commit collection.
*
* The **toSha** is the merge-base of [releaseBranch] and `develop` — the point where the current
* release branched off (i.e. all commits up to and including the version bump commit).
* The **toSha** is the merge-base of `origin/`[releaseBranch] and `origin/develop` — the point
* where the current release branched off (i.e. all commits up to and including the version bump
* commit).
*
* The **fromSha** is the merge-base of [prevReleaseBranch] and `develop` — the point where the
* *previous* release branched off. If the previous release branch doesn't exist (first release),
* falls back to the very first commit on `develop`.
* The **fromSha** is the merge-base of `origin/`[prevReleaseBranch] and `origin/develop` — the
* point where the *previous* release branched off. If the previous release branch doesn't exist on
* the remote, falls back to the very first commit on `develop`.
*
* Both release branch refs are referenced as remote tracking refs (`origin/release-X.Y`) rather
* than local branch names. `actions/checkout` with `fetch-depth: 0` fetches all remote tracking
* refs, so no explicit `git fetch` step is required in the workflow.
*
* @param prevMinor the previous minor version number, used to detect the first-release edge case
* @return a (fromSha, toSha) pair of full commit SHAs
Expand All @@ -235,13 +242,18 @@ fun findCommitRange(
prevReleaseBranch: String,
prevMinor: Int
): Pair<String, String> {
val toSha = gitMergeBase(workspaceRoot, commandExecutor, releaseBranch, "$REMOTE/$DEVELOP_BRANCH")
val toSha =
gitMergeBase(
workspaceRoot, commandExecutor, "$REMOTE/$releaseBranch", "$REMOTE/$DEVELOP_BRANCH"
)
val fromSha = if (prevMinor <= 0) {
// First-ever release: include all commits from the beginning of develop.
gitFirstCommit(workspaceRoot, commandExecutor)
} else {
try {
gitMergeBase(workspaceRoot, commandExecutor, prevReleaseBranch, "$REMOTE/$DEVELOP_BRANCH")
gitMergeBase(
workspaceRoot, commandExecutor, "$REMOTE/$prevReleaseBranch", "$REMOTE/$DEVELOP_BRANCH"
)
} catch (e: IllegalStateException) {
// Re-throw if this isn't a "branch not found" failure — don't mask unrelated errors.
if ("unknown revision" !in (e.message ?: "") &&
Expand Down Expand Up @@ -532,8 +544,7 @@ fun createOrUpdateChangelogPr(
"--base", "develop",
"--head", branchName,
"--title", prTitle,
"--body", prBody,
"--label", "automated-changelog"
"--body", prBody
)
if (result.exitCode == 0) {
val prUrl = result.output.lastOrNull { it.startsWith("https://") } ?: "(URL not found)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,18 @@ class GenerateChangelogsTest {
}

@Test
fun testMain_fourArguments_throwsWithUsageMessage() {
fun testMain_twoArguments_throwsWithUsageMessage() {
val exception =
assertThrows<IllegalArgumentException> { main(arrayOf("a", "b", "c", "d")) }
assertThrows<IllegalArgumentException> { main(arrayOf("a", "b")) }

assertThat(exception).hasMessageThat().contains("Usage:")
}

@Test
fun testMain_sevenArguments_throwsWithUsageMessage() {
fun testMain_fiveArguments_throwsWithUsageMessage() {
val exception =
assertThrows<IllegalArgumentException> {
main(arrayOf("a", "b", "c", "d", "e", "f", "g"))
main(arrayOf("a", "b", "c", "d", "e"))
}

assertThat(exception).hasMessageThat().contains("Usage:")
Expand Down Expand Up @@ -593,7 +593,7 @@ class GenerateChangelogsTest {
@Test
fun testGenerateChangelogs_prevBranchAmbiguousArgument_fallsBackToFirstCommit() {
// Simulates the second git error phrase that indicates a missing branch:
// "ambiguous argument" (e.g. git merge-base release-0.16 origin/develop).
// "ambiguous argument" (e.g. git merge-base origin/release-0.16 origin/develop).
writeVersionBzl(major = 0, minor = 18)
val firstCommit = "firstcommitsha"
val toSha = "toshasha456"
Expand Down
Loading