Skip to content

Commit 26c6248

Browse files
authored
Merge pull request #206 from contentstack/development
DX | 22-06-2026 | Release
2 parents b0df011 + 9ee02e2 commit 26c6248

15 files changed

Lines changed: 833 additions & 51 deletions
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Back-merge master to development
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
pull-requests: write
12+
13+
jobs:
14+
open-back-merge-pr:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0
21+
22+
- name: Open back-merge PR if needed
23+
env:
24+
GH_TOKEN: ${{ github.token }}
25+
run: |
26+
set -euo pipefail
27+
BASE_BRANCH="development"
28+
SOURCE_BRANCH="master"
29+
30+
git fetch origin "$BASE_BRANCH" "$SOURCE_BRANCH"
31+
32+
if ! git show-ref --verify --quiet "refs/remotes/origin/$BASE_BRANCH"; then
33+
echo "Base branch '$BASE_BRANCH' does not exist on origin; skipping."
34+
exit 0
35+
fi
36+
37+
SOURCE_SHA=$(git rev-parse "origin/$SOURCE_BRANCH")
38+
BASE_SHA=$(git rev-parse "origin/$BASE_BRANCH")
39+
40+
if [ "$SOURCE_SHA" = "$BASE_SHA" ]; then
41+
echo "$SOURCE_BRANCH and $BASE_BRANCH are at the same commit; nothing to back-merge."
42+
exit 0
43+
fi
44+
45+
EXISTING=$(gh pr list --repo "${{ github.repository }}" --base "$BASE_BRANCH" --head "$SOURCE_BRANCH" --state open --json number --jq 'length')
46+
47+
if [ "$EXISTING" -gt 0 ]; then
48+
echo "An open PR from $SOURCE_BRANCH to $BASE_BRANCH already exists; skipping."
49+
exit 0
50+
fi
51+
52+
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."
53+
54+
echo "Created back-merge PR $SOURCE_BRANCH -> $BASE_BRANCH."

.github/workflows/check-branch.yml

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
name: Check Version Bump
2+
3+
on:
4+
pull_request:
5+
6+
jobs:
7+
version-bump:
8+
name: Version & Changelog bump
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Checkout
12+
uses: actions/checkout@v4
13+
with:
14+
fetch-depth: 0
15+
16+
- name: Detect changed files and version bump
17+
id: detect
18+
run: |
19+
if git rev-parse HEAD^2 >/dev/null 2>&1; then
20+
FILES=$(git diff --name-only HEAD^1 HEAD^2)
21+
else
22+
FILES=$(git diff --name-only HEAD~1 HEAD)
23+
fi
24+
VERSION_FILES_CHANGED=false
25+
echo "$FILES" | grep -qx 'package.json' && VERSION_FILES_CHANGED=true
26+
echo "$FILES" | grep -qx 'CHANGELOG.md' && VERSION_FILES_CHANGED=true
27+
echo "version_files_changed=$VERSION_FILES_CHANGED" >> $GITHUB_OUTPUT
28+
# Only lib/, webpack/, dist/, package.json count as release-affecting; .github/ and test/ do not
29+
CODE_CHANGED=false
30+
echo "$FILES" | grep -qE '^lib/|^webpack/|^dist/' && CODE_CHANGED=true
31+
echo "$FILES" | grep -qx 'package.json' && CODE_CHANGED=true
32+
echo "code_changed=$CODE_CHANGED" >> $GITHUB_OUTPUT
33+
34+
- name: Skip when only test/docs/.github changed
35+
if: steps.detect.outputs.code_changed != 'true'
36+
run: |
37+
echo "No release-affecting files changed (e.g. only test/docs/.github). Skipping version-bump check."
38+
exit 0
39+
40+
- name: Fail when version bump was missed
41+
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed != 'true'
42+
run: |
43+
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."
44+
exit 1
45+
46+
- name: Setup Node
47+
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true'
48+
uses: actions/setup-node@v4
49+
with:
50+
node-version: '22.x'
51+
52+
- name: Check version bump
53+
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true'
54+
run: |
55+
set -e
56+
PKG_VERSION=$(node -p "require('./package.json').version.replace(/^v/, '')")
57+
if [ -z "$PKG_VERSION" ]; then
58+
echo "::error::Could not read version from package.json"
59+
exit 1
60+
fi
61+
git fetch --tags --force 2>/dev/null || true
62+
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
63+
if [ -z "$LATEST_TAG" ]; then
64+
echo "No existing tags found. Skipping version-bump check (first release)."
65+
exit 0
66+
fi
67+
LATEST_VERSION="${LATEST_TAG#v}"
68+
LATEST_VERSION="${LATEST_VERSION%%-*}"
69+
if [ "$(printf '%s\n' "$LATEST_VERSION" "$PKG_VERSION" | sort -V | tail -1)" != "$PKG_VERSION" ]; then
70+
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."
71+
exit 1
72+
fi
73+
if [ "$PKG_VERSION" = "$LATEST_VERSION" ]; then
74+
echo "::error::Version bump required: package.json version ($PKG_VERSION) equals latest tag ($LATEST_TAG). Please bump the version in package.json."
75+
exit 1
76+
fi
77+
CHANGELOG_VERSION=$(sed -nE 's/^## \[v?([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' CHANGELOG.md | head -1)
78+
if [ -z "$CHANGELOG_VERSION" ]; then
79+
echo "::error::Could not find a version entry in CHANGELOG.md (expected line like '## [v1.0.0](...)')."
80+
exit 1
81+
fi
82+
if [ "$CHANGELOG_VERSION" != "$PKG_VERSION" ]; then
83+
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."
84+
exit 1
85+
fi
86+
echo "Version bump check passed: package.json and CHANGELOG.md are at $PKG_VERSION (latest tag: $LATEST_TAG)."

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,4 @@ venv.bak/
118118
.mypy_cache/
119119
.idea/
120120
.vscode/
121+
*/assets/regions.json

CHANGELOG.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
# CHANGELOG
22

3-
## _v2.5.3_
4-
5-
### **Date: 08-June-2026**
6-
7-
- Fixed security issues.
8-
9-
## _v2.5.2_
10-
11-
### **Date: 18-May-2026**
12-
13-
- Bumped urllib3 in development requirements to address reported vulnerabilities.
3+
## _v2.6.0_
4+
5+
### **Date: 22-June-2026**
6+
7+
- Dynamic endpoint resolution via new `Endpoint` class.
8+
- Region-to-URL mapping is now loaded from a bundled `regions.json` (sourced from `artifacts.contentstack.com`) instead of hardcoded `if/elif` chains.
9+
- Added `Endpoint.get_contentstack_endpoint(region, service, omit_https)` — resolves any supported region to its `contentDelivery`, `contentManagement`, or other service URL.
10+
- Added `contentstack.get_contentstack_endpoint()` module-level proxy.
11+
- `Stack` now auto-resolves `host` and `live_preview` management host via `Endpoint` on initialization.
12+
- Bundled `contentstack/assets/regions.json` included in `package_data` — always present after `pip install`.
13+
- `setup.py` auto-refreshes `regions.json` at build time via a custom `BuildPyWithRegions` command; network failures warn but never block the build.
14+
- Runtime fallback: if `regions.json` is absent, the SDK downloads it live on the first `Endpoint` call.
15+
- Added `refresh_regions()` utility to programmatically download the latest regions manifest from the Contentstack CDN and overwrite the bundled `assets/regions.json` (`from contentstack import refresh_regions`).
16+
- Added `python3 -m contentstack.region_refresh` CLI command for refreshing the registry after `pip install` (source-tree script `scripts/download_regions.py` is for contributors only).
1417

1518
## _v2.5.1_
1619

contentstack/__init__.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,43 @@
66
from .entry import Entry
77
from .asset import Asset
88
from .contenttype import ContentType
9+
from .endpoint import Endpoint
910
from .https_connection import HTTPSConnection
1011
from contentstack.stack import Stack
1112
from .utility import Utils
13+
from .region_refresh import refresh_regions
1214

1315
__all__ = (
1416
"Entry",
1517
"Asset",
1618
"ContentType",
19+
"Endpoint",
1720
"HTTPSConnection",
1821
"Stack",
19-
"Utils"
22+
"Utils",
23+
"refresh_regions",
2024
)
2125

26+
27+
def get_contentstack_endpoint(region='us', service='', omit_https=False):
28+
"""
29+
Resolve a Contentstack service endpoint URL for a given region.
30+
31+
Proxy to :class:`Endpoint.get_contentstack_endpoint` for convenience —
32+
mirrors ``Contentstack::getContentstackEndpoint()`` in the PHP SDK.
33+
34+
:param region: Region ID or alias ('us', 'eu', 'azure-na', 'gcp-eu', ...).
35+
:param service: Service key ('contentDelivery', 'contentManagement', ...).
36+
When empty, returns a dict of all endpoints for the region.
37+
:param omit_https: When True, strips 'https://' from the returned URL(s).
38+
:returns: str when service is provided, dict[str,str] otherwise.
39+
"""
40+
return Endpoint.get_contentstack_endpoint(region, service, omit_https)
41+
2242
__title__ = 'contentstack-delivery-python'
2343
__author__ = 'contentstack'
2444
__status__ = 'debug'
25-
__version__ = 'v2.5.3'
45+
__version__ = 'v2.6.0'
2646
__endpoint__ = 'cdn.contentstack.io'
2747
__email__ = 'support@contentstack.com'
2848
__developer_email__ = 'mobile@contentstack.com'

contentstack/contenttype.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
# ************* Module ContentType **************
99
# Your code has been rated at 10.00/10 by pylint
10+
from __future__ import annotations
1011
import json
1112
import logging
1213
from urllib import parse

0 commit comments

Comments
 (0)