diff --git a/.cursor/rules/README.md b/.cursor/rules/README.md new file mode 100644 index 00000000..f5c1f870 --- /dev/null +++ b/.cursor/rules/README.md @@ -0,0 +1,5 @@ +# Cursor (optional) + +**Cursor** users: start at **[AGENTS.md](../../AGENTS.md)**. All conventions live in **`skills/*/SKILL.md`**. + +This folder only points contributors to **`AGENTS.md`** so editor-specific config does not duplicate the canonical docs. diff --git a/.cursor/rules/dev-workflow.md b/.cursor/rules/dev-workflow.md index 14a02d6a..0d71b365 100644 --- a/.cursor/rules/dev-workflow.md +++ b/.cursor/rules/dev-workflow.md @@ -5,7 +5,7 @@ Use this as the standard workflow when contributing to the Android CDA SDK. ## Branches - Use feature branches for changes (e.g. `feat/...`, `fix/...`). -- Base work off the appropriate long-lived branch (e.g. `staging`, `development`) per team norms. +- Base work off the appropriate long-lived branch (e.g. `development`) per team norms. ## Running tests diff --git a/.github/workflows/back-merge-pr.yml b/.github/workflows/back-merge-pr.yml new file mode 100644 index 00000000..02b378ce --- /dev/null +++ b/.github/workflows/back-merge-pr.yml @@ -0,0 +1,54 @@ +name: Back-merge master to development + +on: + push: + branches: + - master + workflow_dispatch: + +permissions: + contents: read + pull-requests: write + +jobs: + open-back-merge-pr: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Open back-merge PR if needed + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + BASE_BRANCH="development" + SOURCE_BRANCH="master" + + git fetch origin "$BASE_BRANCH" "$SOURCE_BRANCH" + + if ! git show-ref --verify --quiet "refs/remotes/origin/$BASE_BRANCH"; then + echo "Base branch '$BASE_BRANCH' does not exist on origin; skipping." + exit 0 + fi + + SOURCE_SHA=$(git rev-parse "origin/$SOURCE_BRANCH") + BASE_SHA=$(git rev-parse "origin/$BASE_BRANCH") + + if [ "$SOURCE_SHA" = "$BASE_SHA" ]; then + echo "$SOURCE_BRANCH and $BASE_BRANCH are at the same commit; nothing to back-merge." + exit 0 + fi + + EXISTING=$(gh pr list --repo "${{ github.repository }}" --base "$BASE_BRANCH" --head "$SOURCE_BRANCH" --state open --json number --jq 'length') + + if [ "$EXISTING" -gt 0 ]; then + echo "An open PR from $SOURCE_BRANCH to $BASE_BRANCH already exists; skipping." + exit 0 + fi + + gh pr create --repo "${{ github.repository }}" --base "$BASE_BRANCH" --head "$SOURCE_BRANCH" --title "chore: back-merge $SOURCE_BRANCH into $BASE_BRANCH" --body "Automated back-merge after changes landed on \\`$SOURCE_BRANCH\\`. Review and merge to keep \\`$BASE_BRANCH\\` in sync." + + echo "Created back-merge PR $SOURCE_BRANCH -> $BASE_BRANCH." diff --git a/.github/workflows/check-branch.yml b/.github/workflows/check-branch.yml deleted file mode 100644 index 8a3a32ab..00000000 --- a/.github/workflows/check-branch.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: 'Check Branch' - -on: - pull_request: - -jobs: - check_branch: - runs-on: ubuntu-latest - steps: - - name: Comment PR - if: github.base_ref == 'master' && github.head_ref != 'staging' - uses: thollander/actions-comment-pull-request@v2 - with: - message: | - We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the staging branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch. - - name: Check branch - if: github.base_ref == 'master' && github.head_ref != 'staging' - run: | - echo "ERROR: We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the staging branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch." - exit 1 \ No newline at end of file diff --git a/.github/workflows/check-version-bump.yml b/.github/workflows/check-version-bump.yml new file mode 100644 index 00000000..8e710002 --- /dev/null +++ b/.github/workflows/check-version-bump.yml @@ -0,0 +1,86 @@ +name: Check Version Bump + +on: + pull_request: + +jobs: + version-bump: + name: Version & Changelog bump + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Detect changed files and version bump + id: detect + run: | + if git rev-parse HEAD^2 >/dev/null 2>&1; then + FILES=$(git diff --name-only HEAD^1 HEAD^2) + else + FILES=$(git diff --name-only HEAD~1 HEAD) + fi + VERSION_FILES_CHANGED=false + echo "$FILES" | grep -qx 'package.json' && VERSION_FILES_CHANGED=true + echo "$FILES" | grep -qx 'CHANGELOG.md' && VERSION_FILES_CHANGED=true + echo "version_files_changed=$VERSION_FILES_CHANGED" >> $GITHUB_OUTPUT + # Only lib/, webpack/, dist/, package.json count as release-affecting; .github/ and test/ do not + CODE_CHANGED=false + echo "$FILES" | grep -qE '^lib/|^webpack/|^dist/' && CODE_CHANGED=true + echo "$FILES" | grep -qx 'package.json' && CODE_CHANGED=true + echo "code_changed=$CODE_CHANGED" >> $GITHUB_OUTPUT + + - name: Skip when only test/docs/.github changed + if: steps.detect.outputs.code_changed != 'true' + run: | + echo "No release-affecting files changed (e.g. only test/docs/.github). Skipping version-bump check." + exit 0 + + - name: Fail when version bump was missed + if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed != 'true' + run: | + echo "::error::This PR has code changes but no version bump. Please bump the version in package.json and add an entry in CHANGELOG.md." + exit 1 + + - name: Setup Node + if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true' + uses: actions/setup-node@v4 + with: + node-version: '22.x' + + - name: Check version bump + if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true' + run: | + set -e + PKG_VERSION=$(node -p "require('./package.json').version.replace(/^v/, '')") + if [ -z "$PKG_VERSION" ]; then + echo "::error::Could not read version from package.json" + exit 1 + fi + git fetch --tags --force 2>/dev/null || true + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true) + if [ -z "$LATEST_TAG" ]; then + echo "No existing tags found. Skipping version-bump check (first release)." + exit 0 + fi + LATEST_VERSION="${LATEST_TAG#v}" + LATEST_VERSION="${LATEST_VERSION%%-*}" + if [ "$(printf '%s\n' "$LATEST_VERSION" "$PKG_VERSION" | sort -V | tail -1)" != "$PKG_VERSION" ]; then + echo "::error::Version bump required: package.json version ($PKG_VERSION) is not greater than latest tag ($LATEST_TAG). Please bump the version in package.json." + exit 1 + fi + if [ "$PKG_VERSION" = "$LATEST_VERSION" ]; then + echo "::error::Version bump required: package.json version ($PKG_VERSION) equals latest tag ($LATEST_TAG). Please bump the version in package.json." + exit 1 + fi + CHANGELOG_VERSION=$(sed -nE 's/^## \[v?([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' CHANGELOG.md | head -1) + if [ -z "$CHANGELOG_VERSION" ]; then + echo "::error::Could not find a version entry in CHANGELOG.md (expected line like '## [v1.0.0](...)')." + exit 1 + fi + if [ "$CHANGELOG_VERSION" != "$PKG_VERSION" ]; then + echo "::error::CHANGELOG version mismatch: CHANGELOG.md top version ($CHANGELOG_VERSION) does not match package.json version ($PKG_VERSION). Please add or update the CHANGELOG entry for $PKG_VERSION." + exit 1 + fi + echo "Version bump check passed: package.json and CHANGELOG.md are at $PKG_VERSION (latest tag: $LATEST_TAG)." diff --git a/AGENTS.md b/AGENTS.md index b450bc4f..0c98bd9c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,54 +1,43 @@ -# Contentstack Android CDA SDK – Agent Guide +# Contentstack Android Delivery SDK – Agent guide -This document is the main entry point for AI agents working in this repository. +**Universal entry point** for contributors and AI agents. Detailed conventions live in **`skills/*/SKILL.md`**. -## Project +## What this repo is -- **Name:** Contentstack Android CDA SDK (contentstack-android) -- **Purpose:** Android client for the Contentstack **Content Delivery API (CDA)**. It fetches content (entries, assets, content types, sync, etc.) from Contentstack for Android apps. -- **Repo:** [contentstack-android](https://github.com/contentstack/contentstack-android) +| Field | Detail | +|--------|--------| +| **Name:** | [contentstack-android](https://github.com/contentstack/contentstack-android) (`com.contentstack.sdk:android`) | +| **Purpose:** | Android library for the Contentstack Content Delivery API (Kotlin/Java consumers via AAR). | +| **Out of scope:** | Not the Java-only or iOS/Swift SDKs—those live in sibling repositories. | -## Tech stack +## Tech stack (at a glance) -- **Languages:** Java (primary SDK source); Kotlin may appear in tests or future code. Target **Java 8** compatibility for the library (see `contentstack/build.gradle`). -- **Build:** Gradle (Android Gradle Plugin), single module **`contentstack`** (AAR). -- **Testing:** JUnit 4, Robolectric (unit tests on JVM), Mockito / PowerMock where used; **androidTest** with AndroidX Test / Espresso for instrumented tests; JaCoCo for coverage (`jacocoTestReport`). -- **HTTP:** **Volley** (`CSHttpConnection`) for much of the CDA traffic; **Retrofit 2 + OkHttp + Gson** for paths such as taxonomy (`Stack`, `APIService`). OkHttp **MockWebServer** in unit tests. +| Area | Details | +|------|---------| +| Language | Kotlin/Java; **compileSdk 34**; Java **17** compile options in `contentstack/build.gradle` | +| Build | Gradle (root `build.gradle`, `settings.gradle`, module **`contentstack/`**) | +| Tests | JUnit, Mockito, Robolectric, AndroidX Test—unit tests under `contentstack/src/test/` | +| Lint / coverage | JaCoCo integrated with debug unit tests (`testCoverageEnabled` on debug) | +| CI | `.github/workflows/check-branch.yml`, `publish-release.yml`, `sca-scan.yml`, `policy-scan.yml`, `codeql-analysis.yml` | -## Main entry points +## Commands (quick reference) -- **`Contentstack`** – Factory: `Contentstack.stack(Context, apiKey, deliveryToken, environment)` (and overloads with `Config`) returns a **`Stack`**. -- **`Stack`** – Main API: content types, entries, queries, assets, sync, etc. -- **`Config`** – Optional configuration: host, version, region, branch, proxy, connection pool, endpoint. -- **Paths:** `contentstack/src/main/java/com/contentstack/sdk/` (production), `contentstack/src/test/java/com/contentstack/sdk/` (unit tests), `contentstack/src/androidTest/java/` (instrumented tests). +| Command type | Command | +|--------------|---------| +| Unit tests (typical) | `./gradlew :contentstack:testDebugUnitTest` (from repo root) | +| Clean | `./gradlew clean` | -## Commands +## Where the documentation lives: skills -Run from the **repository root** (requires Android SDK / `local.properties` for connected tests). +| Skill | Path | What it covers | +|-------|------|----------------| +| **Development workflow** | [`skills/dev-workflow/SKILL.md`](skills/dev-workflow/SKILL.md) | Gradle, variants, CI, publishing | +| **Android CDA SDK** | [`skills/contentstack-android-cda/SKILL.md`](skills/contentstack-android-cda/SKILL.md) | Library API and module boundaries | +| **Android project layout** | [`skills/android/SKILL.md`](skills/android/SKILL.md) | `contentstack/` module, manifest, BuildConfig | +| **Testing** | [`skills/testing/SKILL.md`](skills/testing/SKILL.md) | Unit vs instrumented tests, Robolectric, JaCoCo | +| **Build & platform** | [`skills/framework/SKILL.md`](skills/framework/SKILL.md) | AGP, signing placeholders, `local.properties` | +| **Code review** | [`skills/code-review/SKILL.md`](skills/code-review/SKILL.md) | PR checklist | -| Goal | Command | -|------|---------| -| **Build library (debug)** | `./gradlew :contentstack:assembleDebug` | -| **Run all unit tests** | `./gradlew :contentstack:testDebugUnitTest` | -| **Run instrumented / connected tests** | `./gradlew :contentstack:connectedDebugAndroidTest` (device or emulator required) | -| **Unit + connected (full local test pass)** | `./gradlew :contentstack:testDebugUnitTest :contentstack:connectedDebugAndroidTest` | -| **Coverage report (unit)** | `./gradlew :contentstack:jacocoTestReport` | - -Instrumented tests may need **`local.properties`** entries (e.g. `APIKey`, `deliveryToken`, `environment`, `host`) for stacks that hit a real CDA endpoint—see `contentstack/build.gradle` `buildConfigField` usage. - -## Rules and skills - -- **`.cursor/rules/`** – Cursor rules for this repo: - - **README.md** – Index of all rules (globs / always-on). - - **dev-workflow.md** – Branches, tests, PR expectations. - - **java.mdc** – Applies to `**/*.java` and `**/*.kt`: language style, `com.contentstack.sdk` layout, logging, null-safety. - - **contentstack-android-cda.mdc** – SDK core: CDA patterns, Stack/Config, host/version/region/branch, retry, callbacks, CDA alignment. - - **testing.mdc** – `contentstack/src/test/**` and `contentstack/src/androidTest/**`: naming, unit vs instrumented, JaCoCo. - - **code-review.mdc** – Always applied: PR/review checklist (aligned with Java CDA SDK). -- **`skills/`** – Reusable skill docs: - - **contentstack-android-cda** – Implementing or changing CDA behavior (Stack/Config, entries, assets, sync, HTTP, callbacks). - - **testing** – Writing or refactoring tests. - - **code-review** – PR review / pre-PR checklist. - - **framework** – Config, HTTP layer (Volley + Retrofit/OkHttp), retry/timeouts. - -Refer to `.cursor/rules/README.md` and `skills/README.md` for details. +## Using Cursor (optional) + +If you use **Cursor**, [`.cursor/rules/README.md`](.cursor/rules/README.md) only points to **`AGENTS.md`**—same docs as everyone else. diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d3c46ed..e2a7f703 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## Version 4.2.2 + +### Date: 01-Jun-2026 + +- Fix: resolved data fetch failure for non-US regions (AZURE_NA, EU, AU, AZURE_EU, GCP_NA, GCP_EU) when connected via VPN by ensuring Stack.URL is correctly synced with the region-specific CDN host after config initialisation. + ## Version 4.2.1 ### Date: 20-Apr-2026 diff --git a/contentstack/build.gradle b/contentstack/build.gradle index 3687fbc6..798afd6e 100755 --- a/contentstack/build.gradle +++ b/contentstack/build.gradle @@ -7,7 +7,7 @@ plugins { ext { PUBLISH_GROUP_ID = 'com.contentstack.sdk' PUBLISH_ARTIFACT_ID = 'android' - PUBLISH_VERSION = '4.2.1' + PUBLISH_VERSION = '4.2.2' } android { diff --git a/contentstack/src/main/java/com/contentstack/sdk/Stack.java b/contentstack/src/main/java/com/contentstack/sdk/Stack.java index eda16a25..43aa73fb 100755 --- a/contentstack/src/main/java/com/contentstack/sdk/Stack.java +++ b/contentstack/src/main/java/com/contentstack/sdk/Stack.java @@ -98,6 +98,7 @@ protected void setConfig(Config config) { } } String endpoint = config.PROTOCOL + config.URL; + URL = config.URL; this.config.setEndpoint(endpoint); client(endpoint); diff --git a/contentstack/src/test/java/com/contentstack/sdk/TestStack.java b/contentstack/src/test/java/com/contentstack/sdk/TestStack.java index a427c858..f6ec85b1 100644 --- a/contentstack/src/test/java/com/contentstack/sdk/TestStack.java +++ b/contentstack/src/test/java/com/contentstack/sdk/TestStack.java @@ -13,7 +13,9 @@ import org.robolectric.annotation.Config; import java.util.Date; +import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.Map; import static org.junit.Assert.*; @@ -360,7 +362,7 @@ public void testStackWithCustomConfig() throws Exception { @Test public void testStackWithDifferentRegions() throws Exception { com.contentstack.sdk.Config.ContentstackRegion[] regions = com.contentstack.sdk.Config.ContentstackRegion.values(); - + for (com.contentstack.sdk.Config.ContentstackRegion region : regions) { com.contentstack.sdk.Config config = new com.contentstack.sdk.Config(); config.setRegion(region); @@ -369,6 +371,36 @@ public void testStackWithDifferentRegions() throws Exception { } } + @Test + public void testAzureNaRegionSetsCorrectURL() throws Exception { + com.contentstack.sdk.Config config = new com.contentstack.sdk.Config(); + config.setRegion(com.contentstack.sdk.Config.ContentstackRegion.AZURE_NA); + Stack regionalStack = Contentstack.stack(mockContext, "api_key", "token", "env", config); + assertEquals("azure-na-cdn.contentstack.com", regionalStack.URL); + } + + @Test + public void testNonUsRegionsSetsCorrectStackURL() throws Exception { + Map expectedHosts = new HashMap<>(); + expectedHosts.put(com.contentstack.sdk.Config.ContentstackRegion.EU, "eu-cdn.contentstack.io"); + expectedHosts.put(com.contentstack.sdk.Config.ContentstackRegion.AU, "au-cdn.contentstack.com"); + expectedHosts.put(com.contentstack.sdk.Config.ContentstackRegion.AZURE_NA, "azure-na-cdn.contentstack.com"); + expectedHosts.put(com.contentstack.sdk.Config.ContentstackRegion.AZURE_EU, "azure-eu-cdn.contentstack.com"); + expectedHosts.put(com.contentstack.sdk.Config.ContentstackRegion.GCP_NA, "gcp-na-cdn.contentstack.com"); + expectedHosts.put(com.contentstack.sdk.Config.ContentstackRegion.GCP_EU, "gcp-eu-cdn.contentstack.com"); + + for (Map.Entry entry : expectedHosts.entrySet()) { + com.contentstack.sdk.Config config = new com.contentstack.sdk.Config(); + config.setRegion(entry.getKey()); + Stack regionalStack = Contentstack.stack(mockContext, "api_key", "token", "env", config); + assertEquals( + "Stack.URL mismatch for region " + entry.getKey(), + entry.getValue(), + regionalStack.URL + ); + } + } + @Test public void testContentTypeEntryCreation() { ContentType contentType = stack.contentType("products"); diff --git a/skills/android/SKILL.md b/skills/android/SKILL.md new file mode 100644 index 00000000..ccb954bd --- /dev/null +++ b/skills/android/SKILL.md @@ -0,0 +1,25 @@ +--- +name: android +description: Use for Android module layout, Gradle config, and Kotlin/Java conventions in contentstack-android. +--- + +# Android project layout – contentstack-android + +## When to use + +- Editing `contentstack/build.gradle`, manifests, or source under `contentstack/src/` +- Adjusting `minSdk`, multidex, or packaging excludes + +## Instructions + +### Source trees + +- Follow standard Android library layout: **`main`**, **`test`**, **`androidTest`** under `contentstack/src/`. + +### Configuration + +- **`local.properties`** supplies machine-specific paths and optional keys—do not commit secrets; use the same keys the Gradle file expects (`host`, `APIKey`, etc. in `buildTypes`). + +### Java/Kotlin + +- Compile options target **Java 17** in the module—match language features accordingly. diff --git a/skills/code-review/SKILL.md b/skills/code-review/SKILL.md index e1e1aab4..fb435841 100644 --- a/skills/code-review/SKILL.md +++ b/skills/code-review/SKILL.md @@ -1,60 +1,27 @@ --- name: code-review -description: Use when reviewing PRs or before opening a PR – API design, null-safety, exceptions, backward compatibility, dependencies, security, and test quality +description: Use when reviewing PRs for contentstack-android—API stability, Gradle, tests, and mobile security. --- -# Code Review – Contentstack Android CDA SDK - -Use this skill when performing or preparing a pull request review for the Android CDA SDK. Aligns with the Java CDA SDK review bar. +# Code review – contentstack-android ## When to use -- Reviewing someone else’s PR. -- Self-reviewing your own PR before submission. -- Checking that changes meet project standards (API, errors, compatibility, tests, security). +- Reviewing feature or fix PRs for the Android SDK +- Auditing dependency or manifest changes ## Instructions -Work through the checklist below. Optionally tag items with severity: **Blocker**, **Major**, **Minor**. - -### 1. API design and stability - -- [ ] **Public API:** New or changed public methods/classes are necessary and documented (Javadoc with purpose and, where relevant, params/returns). -- [ ] **Backward compatibility:** No breaking changes to public API unless explicitly agreed (e.g. major version). Deprecations should have alternatives and timeline. -- [ ] **Naming:** Consistent with existing SDK style and CDA terminology (e.g. `Stack`, `Entry`, `Query`, `Config`). - -**Severity:** Breaking public API without approval = Blocker. Missing docs on new public API = Major. - -### 2. Error handling and robustness - -- [ ] **Errors:** API failures are mapped to the SDK `Error` type and passed through existing callback/result patterns (e.g. `ResultCallBack`). -- [ ] **Null safety:** No unintended NPEs; document or validate parameters for public API where it matters. -- [ ] **Exceptions:** Checked exceptions are handled or declared; use of unchecked exceptions is intentional and documented where relevant. - -**Severity:** Wrong or missing error handling in new code = Major. - -### 3. Dependencies and security - -- [ ] **Dependencies:** New or upgraded dependencies are justified. Version bumps are intentional and do not introduce known vulnerabilities. -- [ ] **SCA:** Any security findings (e.g. Snyk, Dependabot) in the change set are addressed or explicitly deferred with a ticket. - -**Severity:** New critical/high vulnerability = Blocker. - -### 4. Testing - -- [ ] **Coverage:** New or modified behavior has corresponding unit and/or instrumented tests. -- [ ] **Conventions:** Tests follow naming (`Test*` for unit tests) and live in `src/test/` or `src/androidTest/` as appropriate. -- [ ] **Quality:** Tests are readable, deterministic (no flakiness), and assert meaningful behavior. - -**Severity:** No tests for new behavior = Blocker. Flaky or weak tests = Major. - -### 5. Optional severity summary +### Checklist -- **Blocker:** Must fix before merge (e.g. breaking API without approval, security issue, no tests for new code). -- **Major:** Should fix (e.g. inconsistent error handling, missing Javadoc on new public API, flaky tests). -- **Minor:** Nice to fix (e.g. style, minor docs, redundant code). +- **API**: Public SDK surface changes justified and documented. +- **Gradle**: Version bumps coherent; no accidental signing or secret commits. +- **Tests**: Unit tests for new logic; consider Robolectric limitations. +- **Manifest/resources**: No unnecessary permissions; ProGuard rules updated if needed. +- **Cross-SDK**: Behavior consistent with Java/Swift where applicable. -## References +### Severity hints -- Project rule: `.cursor/rules/code-review.mdc` -- Testing skill: `skills/testing/SKILL.md` for test standards +- **Blocker**: Broken `:contentstack:testDebugUnitTest`, leaked credentials, or broken publish metadata. +- **Major**: Missing coverage for risky network or caching changes. +- **Minor**: Formatting, comments, internal refactors. diff --git a/skills/contentstack-android-cda/SKILL.md b/skills/contentstack-android-cda/SKILL.md index 49d10f95..1583fb27 100644 --- a/skills/contentstack-android-cda/SKILL.md +++ b/skills/contentstack-android-cda/SKILL.md @@ -1,53 +1,25 @@ --- name: contentstack-android-cda -description: Use when implementing or changing CDA features – Stack/Config, entries, assets, sync, HTTP, callbacks, and Content Delivery API alignment +description: Use for the public Android Content Delivery SDK surface and package com.contentstack.sdk. --- -# Contentstack Android CDA SDK – CDA Implementation - -Use this skill when implementing or changing Content Delivery API (CDA) behavior in the Android SDK. +# Android CDA SDK – contentstack-android ## When to use -- Adding or modifying Stack, Entry, Query, Asset, Content Type, or Sync behavior. -- Changing Config options (host, version, region, branch, proxy, connection pool). -- Working with the HTTP layer (CSHttpConnection/Volley, Stack/APIService/Retrofit/OkHttp) or callbacks and Error handling. +- Changing SDK entry points consumed by Android apps +- Working with stack configuration, entries, or HTTP client usage in this module ## Instructions -### Stack and Config - -- **Entry point:** `Contentstack.stack(Context, apiKey, deliveryToken, environment)`. Overloads accept `Config` for host, version, region, branch, proxy, connection pool, endpoint. -- **Defaults:** host `cdn.contentstack.io`, version `v3` (see `Config`). Region and branch via `Config.setRegion()`, `Config.setBranch()`. -- **Reference:** `Contentstack.java`, `Stack.java`, `Config.java`. - -### CDA resources - -- **Entries:** `Stack.contentType(uid).entry(uid)`, query APIs, and entry fetch. Use existing `Entry`, `Query`, `EntriesModel`, and callback types. -- **Assets:** `Stack.assetLibrary()`, asset fetch and query. Use `Asset`, `AssetLibrary`, `AssetModel`, and related callbacks. -- **Content types:** Content type schema and listing. Use `ContentType`, `ContentTypesModel`, `ContentTypesCallback`. -- **Sync:** Sync API usage. Use existing sync request/response and pagination patterns. -- **Official API:** Align with [Content Delivery API](https://www.contentstack.com/docs/apis/content-delivery-api/) for parameters, response shape, and semantics. - -### HTTP and retry - -- **HTTP:** CDA requests use **CSHttpConnection** (Volley) and/or **Retrofit** + **OkHttp** (e.g. `Stack`, `APIService`). Set headers (User-Agent, auth) per constants and existing request building. -- **Retry:** Volley retry is configured via `DefaultRetryPolicy` in `CSHttpConnection`; constants in `SDKConstant` (e.g. `TimeOutDuration`, `NumRetry`, `BackOFMultiplier`). Keep timeouts and retry behavior consistent when changing the HTTP layer. -- **Reference:** `CSHttpConnection.java`, `CSConnectionRequest.java`, `Stack.java`, `APIService.java`, `SDKConstant.java`. - -### Errors and callbacks +### Module -- **Errors:** Map API errors to the `Error` class. Pass to the appropriate callback (e.g. `ResultCallBack`) so callers receive a consistent error shape. -- **Callbacks:** Use existing callback types (`ResultCallBack`, `EntryResultCallBack`, `QueryResultsCallBack`, etc.). Do not change callback contracts without considering backward compatibility. +- Primary code lives in **`contentstack/`** with namespace **`com.contentstack.sdk`** (`android { namespace ... }`). -## Key classes +### API design -- **Entry points:** `Contentstack`, `Stack`, `Config` -- **CDA:** `Entry`, `Query`, `Asset`, `AssetLibrary`, `ContentType`, sync-related classes -- **HTTP:** `CSHttpConnection`, `CSConnectionRequest`, `APIService`, `Stack` (Retrofit) -- **Errors / results:** `Error`, `QueryResult`, and callback interfaces in `com.contentstack.sdk` +- Keep public Java/Kotlin APIs stable for app developers—use semver for breaking changes in published AARs. -## References +### Integration -- [Content Delivery API – Contentstack Docs](https://www.contentstack.com/docs/apis/content-delivery-api/) -- Project rules: `.cursor/rules/contentstack-android-cda.mdc`, `.cursor/rules/java.mdc` +- Behavior should stay aligned with other CDA SDKs where features overlap (queries, preview, etc.)—check parity with Java/Swift docs when adding features. diff --git a/skills/dev-workflow/SKILL.md b/skills/dev-workflow/SKILL.md new file mode 100644 index 00000000..ab067442 --- /dev/null +++ b/skills/dev-workflow/SKILL.md @@ -0,0 +1,26 @@ +--- +name: dev-workflow +description: Use for Gradle tasks, CI, release publishing, and branch flow in contentstack-android. +--- + +# Development workflow – contentstack-android + +## When to use + +- Running local builds/tests before a PR +- Aligning with GitHub Actions (branch checks, SCA, publish) + +## Instructions + +### Project shape + +- Root project **`contentstack-android`** includes module **`:contentstack`** (`settings.gradle`). + +### Commands + +- From repo root: `./gradlew :contentstack:testDebugUnitTest` for JVM unit tests on the library. +- Use `./gradlew clean` when switching branches or after AGP/cache issues. + +### CI + +- Workflows under `.github/workflows/` enforce policies and may publish artifacts—coordinate version bumps with `contentstack/build.gradle` `PUBLISH_*` fields. diff --git a/skills/framework/SKILL.md b/skills/framework/SKILL.md index bb58d812..e176b472 100644 --- a/skills/framework/SKILL.md +++ b/skills/framework/SKILL.md @@ -1,52 +1,25 @@ --- name: framework -description: Use when touching config or HTTP layer – Config, CSHttpConnection (Volley), Stack/APIService (Retrofit/OkHttp), timeouts, retry, and error handling +description: Use for AGP, Gradle plugins, JaCoCo, signing, and native Android build concerns in contentstack-android. --- -# Framework – Contentstack Android CDA SDK - -Use this skill when changing configuration or the HTTP connection layer (Volley and/or Retrofit/OkHttp). +# Build & platform – contentstack-android ## When to use -- Modifying **Config** options (host, version, region, branch, proxy, connection pool, endpoint). -- Changing **CSHttpConnection** (Volley), request building, or **Stack**’s Retrofit/OkHttp setup. -- Changing retry/timeout constants (e.g. `SDKConstant.TimeOutDuration`, `NumRetry`, `BackOFMultiplier`) or `DefaultRetryPolicy` usage. -- Introducing or changing connection pooling, timeouts, or interceptors. +- Upgrading Android Gradle Plugin, compile SDK, or dependencies +- Fixing signing, packaging excludes, or multidex issues ## Instructions -### Config - -- **Config** holds: host (default `cdn.contentstack.io`), version (default `v3`), environment, branch, region (`ContentstackRegion`), proxy, connection pool, endpoint, earlyAccess. -- Use setter-style APIs (e.g. `setHost`, `setBranch`, `setRegion`). Preserve default values where existing behavior depends on them. -- **Reference:** `contentstack/src/main/java/com/contentstack/sdk/Config.java`. - -### Volley and CSHttpConnection - -- **CSHttpConnection** uses **Volley** to execute requests. It is invoked via **CSConnectionRequest**; responses and errors are passed to the request’s callback (e.g. `onRequestFinished`). -- **Retry:** Volley’s `DefaultRetryPolicy` is used in `CSHttpConnection` with constants from **SDKConstant** (e.g. `TimeOutDuration`, `NumRetry`, `BackOFMultiplier`). Keep retry/timeout behavior consistent when changing this path. -- **Reference:** `CSHttpConnection.java`, `CSConnectionRequest.java`, `IRequestModelHTTP.java`, `SDKConstant.java`. - -### Stack, Retrofit, and OkHttp - -- **Stack** builds an **OkHttpClient** and **Retrofit** instance and uses **APIService** for certain CDA calls (e.g. taxonomy). Base URL and headers are derived from Config/stack state. -- Do not bypass the shared client/Config when adding new CDA calls that use Retrofit. -- **Reference:** `Stack.java`, `APIService.java`. - -### Error handling +### Gradle -- Map HTTP and API errors to the **Error** class. Pass errors through the same callback mechanism used elsewhere so callers get a consistent contract. -- **Reference:** `Error.java`, and callback interfaces that receive errors. +- Root **`build.gradle`** pins AGP and Nexus publish plugin versions; module plugin **`com.android.library`** applies in `contentstack/build.gradle`. -## Key classes +### Publishing -- **Config:** `Config.java`, `ContentstackRegion` -- **Volley path:** `CSHttpConnection.java`, `CSConnectionRequest.java`, `IRequestModelHTTP.java`, `SDKConstant.java` -- **Retrofit path:** `Stack.java`, `APIService.java` -- **Errors/callbacks:** `Error.java`, `ResultCallBack`, and related callback types +- Maven coordinates use `PUBLISH_GROUP_ID`, `PUBLISH_ARTIFACT_ID`, `PUBLISH_VERSION`—bump with releases. -## References +### Keystore -- Project rules: `.cursor/rules/contentstack-android-cda.mdc`, `.cursor/rules/java.mdc` -- CDA skill: `skills/contentstack-android-cda/SKILL.md` for CDA-specific usage of Config and HTTP +- Debug/release signing references **`key.keystore`** in the module—suitable for sample/debug only; production signing is consumer responsibility. diff --git a/skills/testing/SKILL.md b/skills/testing/SKILL.md index 007bb724..759d280a 100644 --- a/skills/testing/SKILL.md +++ b/skills/testing/SKILL.md @@ -1,49 +1,29 @@ --- name: testing -description: Use when writing or refactoring tests – JUnit 4, Robolectric, androidTest, naming, MockWebServer, JaCoCo +description: Use for JVM unit tests, Robolectric, AndroidX Test, and JaCoCo in contentstack-android. --- -# Testing – Contentstack Android CDA SDK - -Use this skill when adding or refactoring tests in the Android CDA SDK. +# Testing – contentstack-android ## When to use -- Writing new unit or instrumented tests. -- Refactoring test layout, base classes, or test utilities. -- Adjusting test configuration (e.g. timeouts, Robolectric, JaCoCo) or coverage. +- Adding tests under `contentstack/src/test/` +- Debugging JaCoCo or unit-test-only failures ## Instructions -### JUnit 4 and layout - -- Use **JUnit 4** (junit:junit). Dependencies are in `contentstack/build.gradle`. -- **Unit tests:** Class name should start with **`Test`** (e.g. `TestEntry`, `TestStack`). Place under `contentstack/src/test/java/com/contentstack/sdk/`. -- **Instrumented tests:** Place under `contentstack/src/androidTest/java/com/contentstack/sdk/`. Use **AndroidJUnitRunner**; naming may follow existing style (e.g. `*TestCase`). - -### Robolectric and unit tests - -- **Robolectric** provides Android context on the JVM. Use it where tests need `Context` (e.g. `Contentstack.stack(context, ...)`). -- For HTTP mocking in unit tests, use **OkHttp MockWebServer** where the SDK uses OkHttp/Retrofit; mock or stub Volley/CSHttpConnection where appropriate. - -### Instrumented tests and credentials +### Unit tests -- **BuildConfig:** Instrumented tests can use `BuildConfig` fields (APIKey, deliveryToken, environment, host) from `local.properties` (see `contentstack/build.gradle`). Do not commit real credentials; document required variables. -- Use **AndroidX Test** and **Espresso** as in the project; avoid flaky tests (timeouts, IdlingResource if needed). +- Prefer **`testDebugUnitTest`** for fast feedback; Robolectric enables Android APIs on JVM where configured. -### Naming and structure +### Instrumentation -- One test class per production class when possible (e.g. `TestEntry` for `Entry`). -- Keep tests deterministic and readable; prefer meaningful assertions over large blocks of setup. +- **`androidTest`** exists for on-device tests—run on emulator/CI when changing UI-adjacent or integration paths. -### Coverage and execution +### Coverage -- **JaCoCo** is configured in `contentstack/build.gradle`. Run `./gradlew :contentstack:jacocoTestReport` for unit-test coverage (e.g. `contentstack/build/reports/jacoco/`). -- **Unit tests:** `./gradlew :contentstack:testDebugUnitTest` -- **Instrumented:** `./gradlew :contentstack:connectedDebugAndroidTest` -- Maintain or improve coverage when changing production code; add tests for new or modified behavior. +- Debug builds enable **`testCoverageEnabled`**—JaCoCo outputs feed into reporting tasks defined in the module `build.gradle`. -## References +### Hygiene -- `contentstack/build.gradle` – test dependencies, testOptions, jacoco -- Project rule: `.cursor/rules/testing.mdc` +- Use **`MockWebserver`** and fixtures for HTTP; avoid embedding real stack credentials in the repo.