contentstack_utils 1.2.4 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/back-merge-pr.yml +59 -0
- data/.github/workflows/check-version-bump.yml +76 -0
- data/.github/workflows/issues-jira.yml +104 -17
- data/.github/workflows/release-gem.yml +5 -2
- data/.gitignore +3 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +32 -12
- data/contentstack_utils.gemspec +2 -2
- data/lib/contentstack_utils/endpoint.rb +96 -0
- data/lib/contentstack_utils/utils.rb +5 -0
- data/lib/contentstack_utils/version.rb +1 -1
- data/skills/code-review/SKILL.md +1 -1
- data/skills/dev-workflow/SKILL.md +2 -2
- data/skills/framework/SKILL.md +1 -1
- data/spec/lib/endpoint_spec.rb +268 -0
- metadata +20 -16
- data/.github/workflows/check-branch.yml +0 -20
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 551ed8d05213501d037c6d1c67e2a318aea27d0f648818f65046ce33772e5a71
|
|
4
|
+
data.tar.gz: 732fc6138fb1a3369e978187d44d5fbbd72411d44b84fd11167cb4736942f671
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e8caa3855dd5be8e6e7e23b462f7263e1ca1d41691fcbe638a949d4cc4aabdd79365aa9ed1dc30a6b296382bb2fe65ed71df0c274b5b3198638215cc09fe80a1
|
|
7
|
+
data.tar.gz: 0be5f0880dcf07efc45d61597f49b0c42161cbc5a0bcabc6d752300fb0360bac501d035784096b73c1341468104bc16086490e736e3b24484fe7ce3bb97dbff1
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Opens a PR from master → development after changes land on master (back-merge).
|
|
2
|
+
#
|
|
3
|
+
# Org/repo Settings → Actions → General → Workflow permissions: read and write
|
|
4
|
+
# (so GITHUB_TOKEN can create pull requests). Or use a PAT in secret GH_TOKEN.
|
|
5
|
+
|
|
6
|
+
name: Back-merge master to development
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
branches: [master]
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
pull-requests: write
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
open-back-merge-pr:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout
|
|
22
|
+
uses: actions/checkout@v4
|
|
23
|
+
with:
|
|
24
|
+
fetch-depth: 0
|
|
25
|
+
|
|
26
|
+
- name: Open back-merge PR if needed
|
|
27
|
+
env:
|
|
28
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
29
|
+
run: |
|
|
30
|
+
set -euo pipefail
|
|
31
|
+
git fetch origin development master
|
|
32
|
+
|
|
33
|
+
MASTER_SHA=$(git rev-parse origin/master)
|
|
34
|
+
DEV_SHA=$(git rev-parse origin/development)
|
|
35
|
+
|
|
36
|
+
if [ "$MASTER_SHA" = "$DEV_SHA" ]; then
|
|
37
|
+
echo "master and development are at the same commit; nothing to back-merge."
|
|
38
|
+
exit 0
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
EXISTING=$(gh pr list --repo "${{ github.repository }}" \
|
|
42
|
+
--base development \
|
|
43
|
+
--head master \
|
|
44
|
+
--state open \
|
|
45
|
+
--json number \
|
|
46
|
+
--jq 'length')
|
|
47
|
+
|
|
48
|
+
if [ "$EXISTING" -gt 0 ]; then
|
|
49
|
+
echo "An open PR from master to development already exists; skipping."
|
|
50
|
+
exit 0
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
gh pr create --repo "${{ github.repository }}" \
|
|
54
|
+
--base development \
|
|
55
|
+
--head master \
|
|
56
|
+
--title "chore: back-merge master into development" \
|
|
57
|
+
--body "Automated back-merge after changes landed on \`master\`. Review and merge to keep \`development\` in sync."
|
|
58
|
+
|
|
59
|
+
echo "Created back-merge PR master → development."
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Runs only when production code under lib/ changes. Version must be > latest v* tag (not vs base branch).
|
|
2
|
+
|
|
3
|
+
name: Check Version Bump
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
check-version-bump:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
with:
|
|
14
|
+
fetch-depth: 0
|
|
15
|
+
- name: Validate version and changelog updates
|
|
16
|
+
shell: bash
|
|
17
|
+
run: |
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
VERSION_FILE="lib/contentstack_utils/version.rb"
|
|
21
|
+
CHANGELOG_FILE="CHANGELOG.md"
|
|
22
|
+
BASE_SHA="${{ github.event.pull_request.base.sha }}"
|
|
23
|
+
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
|
|
24
|
+
|
|
25
|
+
mapfile -t CHANGED_FILES < <(git diff --name-only "$BASE_SHA" "$HEAD_SHA")
|
|
26
|
+
if [ "${#CHANGED_FILES[@]}" -eq 0 ]; then
|
|
27
|
+
echo "No changed files detected."
|
|
28
|
+
exit 0
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
is_production_source_change() {
|
|
32
|
+
local f="$1"
|
|
33
|
+
[[ "$f" == lib/* ]]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
has_source_changes=false
|
|
37
|
+
for file in "${CHANGED_FILES[@]}"; do
|
|
38
|
+
if is_production_source_change "$file"; then
|
|
39
|
+
has_source_changes=true
|
|
40
|
+
break
|
|
41
|
+
fi
|
|
42
|
+
done
|
|
43
|
+
|
|
44
|
+
if [ "$has_source_changes" = false ]; then
|
|
45
|
+
echo "Skipping: no lib/ production code changes."
|
|
46
|
+
exit 0
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
changed_file() {
|
|
50
|
+
local target="$1"
|
|
51
|
+
for file in "${CHANGED_FILES[@]}"; do
|
|
52
|
+
if [ "$file" = "$target" ]; then
|
|
53
|
+
return 0
|
|
54
|
+
fi
|
|
55
|
+
done
|
|
56
|
+
return 1
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
changed_file "$VERSION_FILE" || { echo "Version bump required in $VERSION_FILE."; exit 1; }
|
|
60
|
+
changed_file "$CHANGELOG_FILE" || { echo "Matching changelog update required in $CHANGELOG_FILE."; exit 1; }
|
|
61
|
+
|
|
62
|
+
head_version=$(sed -nE 's/.*VERSION\s*=\s*["'"'"']([^"'"'"']+)["'"'"'].*/\1/p' "$VERSION_FILE" | sed -n '1p')
|
|
63
|
+
CHANGELOG_HEAD=$(sed -nE 's/^## v?\[?([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' "$CHANGELOG_FILE" | head -1)
|
|
64
|
+
|
|
65
|
+
[ -n "$CHANGELOG_HEAD" ] || { echo "::error::Could not find a top changelog heading like '## vX.Y.Z' in $CHANGELOG_FILE."; exit 1; }
|
|
66
|
+
[ "$CHANGELOG_HEAD" = "$head_version" ] || { echo "::error::$CHANGELOG_FILE top version ($CHANGELOG_HEAD) does not match project version ($head_version)."; exit 1; }
|
|
67
|
+
|
|
68
|
+
latest_tag=$(git tag --list 'v*' --sort=-version:refname | sed -n '1p')
|
|
69
|
+
latest_version="${latest_tag#v}"
|
|
70
|
+
[ -n "$latest_version" ] || latest_version="0.0.0"
|
|
71
|
+
|
|
72
|
+
version_gt() {
|
|
73
|
+
python3 -c 'import sys;v=lambda s:[int(x) if x.isdigit() else 0 for x in (s.strip().lstrip("v").split("-",1)[0].split("+",1)[0].split(".")+["0","0","0"])[:3]];print("true" if v(sys.argv[1])>v(sys.argv[2]) else "false")' "$1" "$2"
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
[ "$(version_gt "$head_version" "$latest_version")" = "true" ] || { echo "Version must be greater than latest tag version ($latest_version). Found $head_version."; exit 1; }
|
|
@@ -2,30 +2,117 @@ name: Create Jira Ticket for Github Issue
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
issues:
|
|
5
|
-
types: [opened]
|
|
5
|
+
types: [opened, reopened]
|
|
6
6
|
|
|
7
7
|
jobs:
|
|
8
8
|
issue-jira:
|
|
9
9
|
runs-on: ubuntu-latest
|
|
10
10
|
steps:
|
|
11
|
+
- name: Create Jira Issue
|
|
12
|
+
id: create_jira
|
|
13
|
+
uses: actions/github-script@v9
|
|
14
|
+
with:
|
|
15
|
+
script: |
|
|
16
|
+
const baseUrl = process.env.JIRA_BASE_URL;
|
|
17
|
+
const userEmail = process.env.JIRA_USER_EMAIL;
|
|
18
|
+
const jiraToken = process.env.JIRA_API_TOKEN;
|
|
19
|
+
const jiraProject = process.env.JIRA_PROJECT;
|
|
20
|
+
const jiraIssueType = process.env.JIRA_ISSUE_TYPE;
|
|
21
|
+
const jiraFields = JSON.parse(process.env.ISSUES_JIRA_FIELDS);
|
|
22
|
+
|
|
23
|
+
let requestBody = JSON.stringify({
|
|
24
|
+
fields: {
|
|
25
|
+
...jiraFields,
|
|
26
|
+
"project": {
|
|
27
|
+
"key": jiraProject
|
|
28
|
+
},
|
|
29
|
+
"issuetype": {
|
|
30
|
+
"name": jiraIssueType
|
|
31
|
+
},
|
|
32
|
+
"summary": "Github | Issue | ${{ github.event.repository.name }} | ${{ github.event.issue.title }}",
|
|
33
|
+
"description": {
|
|
34
|
+
"version": 1,
|
|
35
|
+
"type": "doc",
|
|
36
|
+
"content": [
|
|
37
|
+
{
|
|
38
|
+
"type": "paragraph",
|
|
39
|
+
"content": [
|
|
40
|
+
{
|
|
41
|
+
"type": "text",
|
|
42
|
+
"text": "Github Issue",
|
|
43
|
+
"marks": [
|
|
44
|
+
{
|
|
45
|
+
"type": "strong"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"type": "text",
|
|
51
|
+
"text": ": "
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"type": "text",
|
|
55
|
+
"text": "${{ github.event.issue.html_url }}",
|
|
56
|
+
"marks": [
|
|
57
|
+
{
|
|
58
|
+
"type": "link",
|
|
59
|
+
"attrs": {
|
|
60
|
+
"href": "${{ github.event.issue.html_url }}"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"type": "paragraph",
|
|
69
|
+
"content": [
|
|
70
|
+
{
|
|
71
|
+
"type": "text",
|
|
72
|
+
"text": "Description",
|
|
73
|
+
"marks": [
|
|
74
|
+
{
|
|
75
|
+
"type": "strong"
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"type": "text",
|
|
81
|
+
"text": ":"
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"type": "codeBlock",
|
|
87
|
+
"content": [
|
|
88
|
+
{
|
|
89
|
+
"type": "text",
|
|
90
|
+
"text": `${{ github.event.issue.body }}`
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
11
98
|
|
|
12
|
-
|
|
13
|
-
|
|
99
|
+
const response = await fetch(`${baseUrl}/rest/api/3/issue`, {
|
|
100
|
+
method: 'POST',
|
|
101
|
+
headers: {
|
|
102
|
+
'Content-Type': 'application/json',
|
|
103
|
+
'Authorization': `Basic ${btoa(userEmail + ":" + jiraToken)}`
|
|
104
|
+
},
|
|
105
|
+
body: requestBody
|
|
106
|
+
});
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
throw new Error(`JIRA API error! Status: ${response.status}`);
|
|
109
|
+
}
|
|
110
|
+
const data = await response.json();
|
|
111
|
+
console.log('Jira Issue Created:', data.key);
|
|
14
112
|
env:
|
|
15
113
|
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
|
16
114
|
JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
|
|
17
115
|
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
uses: atlassian/gajira-create@master
|
|
22
|
-
with:
|
|
23
|
-
project: ${{ secrets.JIRA_PROJECT }}
|
|
24
|
-
issuetype: ${{ secrets.JIRA_ISSUE_TYPE }}
|
|
25
|
-
summary: Github | Issue | ${{ github.event.repository.name }} | ${{ github.event.issue.title }}
|
|
26
|
-
description: |
|
|
27
|
-
*GitHub Issue:* ${{ github.event.issue.html_url }}
|
|
28
|
-
|
|
29
|
-
*Description:*
|
|
30
|
-
${{ github.event.issue.body }}
|
|
31
|
-
fields: "${{ secrets.ISSUES_JIRA_FIELDS }}"
|
|
116
|
+
JIRA_PROJECT: ${{ secrets.JIRA_PROJECT }}
|
|
117
|
+
JIRA_ISSUE_TYPE: ${{ secrets.JIRA_ISSUE_TYPE }}
|
|
118
|
+
ISSUES_JIRA_FIELDS: "${{ secrets.ISSUES_JIRA_FIELDS }}"
|
|
@@ -6,6 +6,7 @@ on:
|
|
|
6
6
|
|
|
7
7
|
jobs:
|
|
8
8
|
build:
|
|
9
|
+
if: ${{ startsWith(github.event.release.tag_name, 'v') && !github.event.release.draft }}
|
|
9
10
|
name: Build + Publish
|
|
10
11
|
runs-on: ubuntu-latest
|
|
11
12
|
permissions:
|
|
@@ -14,10 +15,12 @@ jobs:
|
|
|
14
15
|
|
|
15
16
|
steps:
|
|
16
17
|
- uses: actions/checkout@v3
|
|
17
|
-
|
|
18
|
+
with:
|
|
19
|
+
ref: ${{ github.event.release.tag_name }}
|
|
20
|
+
- name: Set up Ruby 3.1
|
|
18
21
|
uses: ruby/setup-ruby@v1
|
|
19
22
|
with:
|
|
20
|
-
ruby-version: '
|
|
23
|
+
ruby-version: '3.1'
|
|
21
24
|
|
|
22
25
|
- name: Publish to RubyGems
|
|
23
26
|
run: |
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.3.11
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.3.0](https://github.com/contentstack/contentstack-utils-ruby/tree/v1.3.0) (2026-06-29)
|
|
4
|
+
- Added `ContentstackUtils::Endpoint.get_contentstack_endpoint` for dynamic endpoint resolution based on region and service.
|
|
5
|
+
- Added `ContentstackUtils.get_contentstack_endpoint` as a backward-compatible proxy.
|
|
6
|
+
- Added `ContentstackUtils::Endpoint.refresh_regions` for manual region metadata refresh.
|
|
7
|
+
- Added runtime fallback to automatically download `regions.json` from the Contentstack Regions Registry when not present locally.
|
|
8
|
+
- Fixed security vulnerabilities: upgraded yard to 0.9.44 (Directory Traversal) and concurrent-ruby to 1.3.7 (Infinite loop, Improper Locking, Wrap-around Error).
|
|
9
|
+
|
|
3
10
|
## [1.2.4](https://github.com/contentstack/contentstack-utils-ruby/tree/v1.2.4) (2026-04-15)
|
|
4
11
|
- Fixed Security issues.
|
|
5
12
|
|
data/Gemfile.lock
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
contentstack_utils (1.
|
|
4
|
+
contentstack_utils (1.3.0)
|
|
5
5
|
activesupport (>= 7.0, < 8)
|
|
6
|
-
nokogiri (
|
|
6
|
+
nokogiri (~> 1.19, >= 1.19.2)
|
|
7
7
|
|
|
8
8
|
GEM
|
|
9
9
|
remote: https://rubygems.org/
|
|
@@ -25,8 +25,8 @@ GEM
|
|
|
25
25
|
base64 (0.3.0)
|
|
26
26
|
benchmark (0.5.0)
|
|
27
27
|
bigdecimal (4.1.1)
|
|
28
|
-
concurrent-ruby (1.3.
|
|
29
|
-
connection_pool (
|
|
28
|
+
concurrent-ruby (1.3.7)
|
|
29
|
+
connection_pool (3.0.2)
|
|
30
30
|
crack (1.0.1)
|
|
31
31
|
bigdecimal
|
|
32
32
|
rexml
|
|
@@ -38,11 +38,25 @@ GEM
|
|
|
38
38
|
concurrent-ruby (~> 1.0)
|
|
39
39
|
logger (1.7.0)
|
|
40
40
|
minitest (5.27.0)
|
|
41
|
-
nokogiri (1.
|
|
41
|
+
nokogiri (1.19.3-aarch64-linux-gnu)
|
|
42
42
|
racc (~> 1.4)
|
|
43
|
-
|
|
43
|
+
nokogiri (1.19.3-aarch64-linux-musl)
|
|
44
|
+
racc (~> 1.4)
|
|
45
|
+
nokogiri (1.19.3-arm-linux-gnu)
|
|
46
|
+
racc (~> 1.4)
|
|
47
|
+
nokogiri (1.19.3-arm-linux-musl)
|
|
48
|
+
racc (~> 1.4)
|
|
49
|
+
nokogiri (1.19.3-arm64-darwin)
|
|
50
|
+
racc (~> 1.4)
|
|
51
|
+
nokogiri (1.19.3-x86_64-darwin)
|
|
52
|
+
racc (~> 1.4)
|
|
53
|
+
nokogiri (1.19.3-x86_64-linux-gnu)
|
|
54
|
+
racc (~> 1.4)
|
|
55
|
+
nokogiri (1.19.3-x86_64-linux-musl)
|
|
56
|
+
racc (~> 1.4)
|
|
57
|
+
public_suffix (7.0.5)
|
|
44
58
|
racc (1.8.1)
|
|
45
|
-
rake (13.4.
|
|
59
|
+
rake (13.4.2)
|
|
46
60
|
rexml (3.4.4)
|
|
47
61
|
rspec (3.13.2)
|
|
48
62
|
rspec-core (~> 3.13.0)
|
|
@@ -70,11 +84,17 @@ GEM
|
|
|
70
84
|
addressable (>= 2.8.0)
|
|
71
85
|
crack (>= 0.3.2)
|
|
72
86
|
hashdiff (>= 0.4.0, < 2.0.0)
|
|
73
|
-
yard (0.9.
|
|
87
|
+
yard (0.9.44)
|
|
74
88
|
|
|
75
89
|
PLATFORMS
|
|
76
|
-
|
|
77
|
-
|
|
90
|
+
aarch64-linux-gnu
|
|
91
|
+
aarch64-linux-musl
|
|
92
|
+
arm-linux-gnu
|
|
93
|
+
arm-linux-musl
|
|
94
|
+
arm64-darwin
|
|
95
|
+
x86_64-darwin
|
|
96
|
+
x86_64-linux-gnu
|
|
97
|
+
x86_64-linux-musl
|
|
78
98
|
|
|
79
99
|
DEPENDENCIES
|
|
80
100
|
contentstack_utils!
|
|
@@ -82,7 +102,7 @@ DEPENDENCIES
|
|
|
82
102
|
rspec (~> 3.13)
|
|
83
103
|
simplecov (~> 0.22)
|
|
84
104
|
webmock (~> 3.23)
|
|
85
|
-
yard (
|
|
105
|
+
yard (>= 0.9.44)
|
|
86
106
|
|
|
87
107
|
BUNDLED WITH
|
|
88
|
-
2.
|
|
108
|
+
2.5.22
|
data/contentstack_utils.gemspec
CHANGED
|
@@ -22,11 +22,11 @@ Gem::Specification.new do |s|
|
|
|
22
22
|
s.require_paths = ["lib"]
|
|
23
23
|
|
|
24
24
|
s.add_dependency 'activesupport', '>= 7.0', '< 8'
|
|
25
|
-
s.add_dependency 'nokogiri', '
|
|
25
|
+
s.add_dependency 'nokogiri', '~> 1.19', '>= 1.19.2'
|
|
26
26
|
|
|
27
27
|
s.add_development_dependency 'rake', '~> 13.0'
|
|
28
28
|
s.add_development_dependency 'rspec', '~> 3.13'
|
|
29
29
|
s.add_development_dependency 'webmock', '~> 3.23'
|
|
30
30
|
s.add_development_dependency 'simplecov', '~> 0.22'
|
|
31
|
-
s.add_development_dependency 'yard', '
|
|
31
|
+
s.add_development_dependency 'yard', '>= 0.9.44'
|
|
32
32
|
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'net/http'
|
|
3
|
+
require 'uri'
|
|
4
|
+
|
|
5
|
+
module ContentstackUtils
|
|
6
|
+
module Endpoint
|
|
7
|
+
REGIONS_URL = 'https://artifacts.contentstack.com/regions.json'
|
|
8
|
+
REGIONS_FILE = File.expand_path('../assets/regions.json', __FILE__)
|
|
9
|
+
|
|
10
|
+
@regions_data = nil
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
def get_contentstack_endpoint(region: 'us', service: '', omit_https: false)
|
|
14
|
+
raise ArgumentError, 'Empty region provided' if region.nil? || region.to_s.strip.empty?
|
|
15
|
+
|
|
16
|
+
normalized = region.to_s.strip.downcase
|
|
17
|
+
regions = load_regions
|
|
18
|
+
|
|
19
|
+
region_row = find_region_by_id_or_alias(regions, normalized)
|
|
20
|
+
raise ArgumentError, "Invalid region: #{region}" if region_row.nil?
|
|
21
|
+
|
|
22
|
+
endpoints = region_row['endpoints']
|
|
23
|
+
|
|
24
|
+
if service.nil? || service.to_s.strip.empty?
|
|
25
|
+
return omit_https ? strip_https_from_map(endpoints) : endpoints.dup
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
url = endpoints[service.to_s]
|
|
29
|
+
raise ArgumentError, "Service \"#{service}\" not found for region \"#{region}\"" if url.nil?
|
|
30
|
+
|
|
31
|
+
omit_https ? strip_https(url) : url
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def refresh_regions
|
|
35
|
+
download_and_save(REGIONS_FILE)
|
|
36
|
+
@regions_data = nil
|
|
37
|
+
load_regions
|
|
38
|
+
true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def reset_cache
|
|
42
|
+
@regions_data = nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def load_regions
|
|
48
|
+
return @regions_data if @regions_data
|
|
49
|
+
|
|
50
|
+
unless File.exist?(REGIONS_FILE)
|
|
51
|
+
download_and_save(REGIONS_FILE)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
raw = File.read(REGIONS_FILE)
|
|
55
|
+
parsed = JSON.parse(raw)
|
|
56
|
+
raise RuntimeError, 'Invalid regions data: missing "regions" key' unless parsed.is_a?(Hash) && parsed['regions']
|
|
57
|
+
|
|
58
|
+
@regions_data = parsed['regions']
|
|
59
|
+
rescue JSON::ParserError => e
|
|
60
|
+
raise RuntimeError, "Failed to parse regions data: #{e.message}"
|
|
61
|
+
rescue Errno::ENOENT => e
|
|
62
|
+
raise RuntimeError, "Failed to read regions file: #{e.message}"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def download_and_save(dest)
|
|
66
|
+
uri = URI.parse(REGIONS_URL)
|
|
67
|
+
response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https', open_timeout: 30, read_timeout: 30) do |http|
|
|
68
|
+
http.get(uri.request_uri)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
raise RuntimeError, "Failed to download regions: HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)
|
|
72
|
+
|
|
73
|
+
parsed = JSON.parse(response.body)
|
|
74
|
+
raise RuntimeError, 'Downloaded regions data is invalid' unless parsed.is_a?(Hash) && parsed['regions']
|
|
75
|
+
|
|
76
|
+
FileUtils.mkdir_p(File.dirname(dest))
|
|
77
|
+
File.write(dest, JSON.pretty_generate(parsed))
|
|
78
|
+
rescue StandardError => e
|
|
79
|
+
raise RuntimeError, "Failed to fetch region metadata: #{e.message}"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def find_region_by_id_or_alias(regions, input)
|
|
83
|
+
regions.find { |r| r['id'] == input } ||
|
|
84
|
+
regions.find { |r| r['alias']&.any? { |a| a.downcase == input } }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def strip_https(url)
|
|
88
|
+
url.sub(%r{\Ahttps?://}, '')
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def strip_https_from_map(endpoints)
|
|
92
|
+
endpoints.transform_values { |url| strip_https(url) }
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require_relative './model/options.rb'
|
|
2
2
|
require_relative './model/metadata.rb'
|
|
3
3
|
require_relative './support/helper.rb'
|
|
4
|
+
require_relative './endpoint.rb'
|
|
4
5
|
require 'nokogiri'
|
|
5
6
|
|
|
6
7
|
module ContentstackUtils
|
|
@@ -136,6 +137,10 @@ module ContentstackUtils
|
|
|
136
137
|
return nil
|
|
137
138
|
end
|
|
138
139
|
|
|
140
|
+
def self.get_contentstack_endpoint(region: 'us', service: '', omit_https: false)
|
|
141
|
+
Endpoint.get_contentstack_endpoint(region: region, service: service, omit_https: omit_https)
|
|
142
|
+
end
|
|
143
|
+
|
|
139
144
|
module GQL
|
|
140
145
|
include ContentstackUtils
|
|
141
146
|
def self.json_to_html(content, options)
|
data/skills/code-review/SKILL.md
CHANGED
|
@@ -33,7 +33,7 @@ description: Use when reviewing or preparing a PR for this gem—behavior, tests
|
|
|
33
33
|
|
|
34
34
|
### Process
|
|
35
35
|
|
|
36
|
-
- Respect **CODEOWNERS** and branch policy (**`
|
|
36
|
+
- Respect **CODEOWNERS** and branch policy (**feature/fix -> `development`**, release PRs **`development` -> `master`**) described in [dev-workflow](../dev-workflow/SKILL.md)
|
|
37
37
|
|
|
38
38
|
## References
|
|
39
39
|
|
|
@@ -32,12 +32,12 @@ description: Use when setting up the dev environment, running build/test/docs, o
|
|
|
32
32
|
|
|
33
33
|
### Branches and PRs
|
|
34
34
|
|
|
35
|
-
-
|
|
35
|
+
- Feature/fix PRs should target **`development`**. Release PRs are raised directly from **`development`** to **`master`**.
|
|
36
36
|
- Use `CODEOWNERS` for required reviewers when applicable
|
|
37
37
|
|
|
38
38
|
### CI and automation (no RSpec workflow today)
|
|
39
39
|
|
|
40
|
-
- **Release:** `.github/workflows/release-gem.yml` — on GitHub **release created
|
|
40
|
+
- **Release:** `.github/workflows/release-gem.yml` — on GitHub **Release** created (`release: types: [created]`) for tag **`v*`** (draft releases skipped), checks out the tag, then builds and pushes to RubyGems (note: workflow pins Ruby 2.7 for publish; align with gemspec minimum when changing)
|
|
41
41
|
- **Security / compliance:** CodeQL, policy scan, SCA scan — see `.github/workflows/`
|
|
42
42
|
- **Issues:** Jira integration workflow in `.github/workflows/issues-jira.yml`
|
|
43
43
|
|
data/skills/framework/SKILL.md
CHANGED
|
@@ -35,7 +35,7 @@ description: Use when changing the gemspec, Bundler setup, Ruby/runtime constrai
|
|
|
35
35
|
### Build and publish
|
|
36
36
|
|
|
37
37
|
- Local artifact: `gem build contentstack_utils.gemspec`
|
|
38
|
-
- Publishing
|
|
38
|
+
- Publishing runs when a GitHub **Release** is created (`release: types: [created]`) for tag **`v*`** (draft releases skipped); see `release-gem.yml`.
|
|
39
39
|
|
|
40
40
|
## References
|
|
41
41
|
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe ContentstackUtils::Endpoint do
|
|
4
|
+
before(:each) do
|
|
5
|
+
described_class.reset_cache
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# ── Default region ──────────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
describe '.get_contentstack_endpoint with defaults' do
|
|
11
|
+
it 'returns a hash when no service is given' do
|
|
12
|
+
result = described_class.get_contentstack_endpoint
|
|
13
|
+
expect(result).to be_a(Hash)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'default region includes contentDelivery and contentManagement' do
|
|
17
|
+
result = described_class.get_contentstack_endpoint
|
|
18
|
+
expect(result).to have_key('contentDelivery')
|
|
19
|
+
expect(result).to have_key('contentManagement')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'default region contentDelivery is NA CDN' do
|
|
23
|
+
result = described_class.get_contentstack_endpoint
|
|
24
|
+
expect(result['contentDelivery']).to eq('https://cdn.contentstack.io')
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# ── NA aliases ──────────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
describe 'NA region aliases' do
|
|
31
|
+
%w[na us aws-na aws_na NA US AWS-NA AWS_NA].each do |alias_val|
|
|
32
|
+
it "alias \"#{alias_val}\" resolves contentDelivery to NA CDN" do
|
|
33
|
+
result = described_class.get_contentstack_endpoint(region: alias_val, service: 'contentDelivery')
|
|
34
|
+
expect(result).to eq('https://cdn.contentstack.io')
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# ── All 7 regions – contentDelivery ─────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
describe 'contentDelivery endpoints per region' do
|
|
42
|
+
{
|
|
43
|
+
'na' => 'https://cdn.contentstack.io',
|
|
44
|
+
'eu' => 'https://eu-cdn.contentstack.com',
|
|
45
|
+
'au' => 'https://au-cdn.contentstack.com',
|
|
46
|
+
'azure-na' => 'https://azure-na-cdn.contentstack.com',
|
|
47
|
+
'azure-eu' => 'https://azure-eu-cdn.contentstack.com',
|
|
48
|
+
'gcp-na' => 'https://gcp-na-cdn.contentstack.com',
|
|
49
|
+
'gcp-eu' => 'https://gcp-eu-cdn.contentstack.com'
|
|
50
|
+
}.each do |region, expected_url|
|
|
51
|
+
it "region \"#{region}\" resolves contentDelivery to #{expected_url}" do
|
|
52
|
+
result = described_class.get_contentstack_endpoint(region: region, service: 'contentDelivery')
|
|
53
|
+
expect(result).to eq(expected_url)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# ── All 7 regions – contentManagement ───────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
describe 'contentManagement endpoints per region' do
|
|
61
|
+
{
|
|
62
|
+
'na' => 'https://api.contentstack.io',
|
|
63
|
+
'eu' => 'https://eu-api.contentstack.com',
|
|
64
|
+
'au' => 'https://au-api.contentstack.com',
|
|
65
|
+
'azure-na' => 'https://azure-na-api.contentstack.com',
|
|
66
|
+
'azure-eu' => 'https://azure-eu-api.contentstack.com',
|
|
67
|
+
'gcp-na' => 'https://gcp-na-api.contentstack.com',
|
|
68
|
+
'gcp-eu' => 'https://gcp-eu-api.contentstack.com'
|
|
69
|
+
}.each do |region, expected_url|
|
|
70
|
+
it "region \"#{region}\" resolves contentManagement to #{expected_url}" do
|
|
71
|
+
result = described_class.get_contentstack_endpoint(region: region, service: 'contentManagement')
|
|
72
|
+
expect(result).to eq(expected_url)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# ── Service keys present ─────────────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
describe 'all service keys present' do
|
|
80
|
+
let(:expected_services) do
|
|
81
|
+
%w[
|
|
82
|
+
application contentDelivery contentManagement auth
|
|
83
|
+
graphqlDelivery preview graphqlPreview images assets
|
|
84
|
+
automate launch developerHub brandKit genAI
|
|
85
|
+
personalizeManagement personalizeEdge composableStudio
|
|
86
|
+
]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'EU region returns all expected service keys' do
|
|
90
|
+
result = described_class.get_contentstack_endpoint(region: 'eu')
|
|
91
|
+
expected_services.each do |svc|
|
|
92
|
+
expect(result).to have_key(svc), "expected key #{svc} to be present"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'NA region additionally includes assetManagement' do
|
|
97
|
+
result = described_class.get_contentstack_endpoint(region: 'na')
|
|
98
|
+
expect(result).to have_key('assetManagement')
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# ── omit_https flag ──────────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
describe 'omit_https option' do
|
|
105
|
+
it 'strips https:// from a single service URL' do
|
|
106
|
+
result = described_class.get_contentstack_endpoint(region: 'na', service: 'contentDelivery', omit_https: true)
|
|
107
|
+
expect(result).to eq('cdn.contentstack.io')
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it 'strips https:// from all endpoints when no service given' do
|
|
111
|
+
result = described_class.get_contentstack_endpoint(region: 'na', omit_https: true)
|
|
112
|
+
result.each_value do |url|
|
|
113
|
+
expect(url).not_to start_with('https://')
|
|
114
|
+
expect(url).not_to start_with('http://')
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it 'retains https:// when omit_https is false (default)' do
|
|
119
|
+
result = described_class.get_contentstack_endpoint(region: 'na', service: 'contentDelivery', omit_https: false)
|
|
120
|
+
expect(result).to start_with('https://')
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'strips https:// from EU contentManagement' do
|
|
124
|
+
result = described_class.get_contentstack_endpoint(region: 'eu', service: 'contentManagement', omit_https: true)
|
|
125
|
+
expect(result).to eq('eu-api.contentstack.com')
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# ── Case-insensitive aliases ─────────────────────────────────────────────────
|
|
130
|
+
|
|
131
|
+
describe 'case-insensitive alias resolution' do
|
|
132
|
+
it 'resolves uppercase AWS-NA alias' do
|
|
133
|
+
result = described_class.get_contentstack_endpoint(region: 'AWS-NA', service: 'contentDelivery')
|
|
134
|
+
expect(result).to eq('https://azure-na-cdn.contentstack.com').or eq('https://cdn.contentstack.io')
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it 'resolves azure_na alias' do
|
|
138
|
+
result = described_class.get_contentstack_endpoint(region: 'azure_na', service: 'contentDelivery')
|
|
139
|
+
expect(result).to eq('https://azure-na-cdn.contentstack.com')
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it 'resolves gcp_eu alias' do
|
|
143
|
+
result = described_class.get_contentstack_endpoint(region: 'gcp_eu', service: 'contentDelivery')
|
|
144
|
+
expect(result).to eq('https://gcp-eu-cdn.contentstack.com')
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it 'resolves AZURE-EU alias' do
|
|
148
|
+
result = described_class.get_contentstack_endpoint(region: 'AZURE-EU', service: 'contentDelivery')
|
|
149
|
+
expect(result).to eq('https://azure-eu-cdn.contentstack.com')
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it 'resolves GCP-NA alias' do
|
|
153
|
+
result = described_class.get_contentstack_endpoint(region: 'GCP-NA', service: 'contentDelivery')
|
|
154
|
+
expect(result).to eq('https://gcp-na-cdn.contentstack.com')
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# ── No-service returns full endpoints hash ───────────────────────────────────
|
|
159
|
+
|
|
160
|
+
describe 'full endpoints map returned when no service specified' do
|
|
161
|
+
it 'AU returns a hash with more than 1 entry' do
|
|
162
|
+
result = described_class.get_contentstack_endpoint(region: 'au')
|
|
163
|
+
expect(result).to be_a(Hash)
|
|
164
|
+
expect(result.size).to be > 1
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it 'AU contentDelivery is correct in the map' do
|
|
168
|
+
result = described_class.get_contentstack_endpoint(region: 'au')
|
|
169
|
+
expect(result['contentDelivery']).to eq('https://au-cdn.contentstack.com')
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it 'returns a copy — mutations do not affect cached data' do
|
|
173
|
+
result = described_class.get_contentstack_endpoint(region: 'na')
|
|
174
|
+
result['contentDelivery'] = 'mutated'
|
|
175
|
+
fresh = described_class.get_contentstack_endpoint(region: 'na')
|
|
176
|
+
expect(fresh['contentDelivery']).to eq('https://cdn.contentstack.io')
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# ── Error cases ──────────────────────────────────────────────────────────────
|
|
181
|
+
|
|
182
|
+
describe 'error cases' do
|
|
183
|
+
it 'raises ArgumentError for empty string region' do
|
|
184
|
+
expect { described_class.get_contentstack_endpoint(region: '') }
|
|
185
|
+
.to raise_error(ArgumentError, 'Empty region provided')
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it 'raises ArgumentError for whitespace-only region' do
|
|
189
|
+
expect { described_class.get_contentstack_endpoint(region: ' ') }
|
|
190
|
+
.to raise_error(ArgumentError, 'Empty region provided')
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
it 'raises ArgumentError for unknown region' do
|
|
194
|
+
expect { described_class.get_contentstack_endpoint(region: 'invalid-region') }
|
|
195
|
+
.to raise_error(ArgumentError, 'Invalid region: invalid-region')
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it 'raises ArgumentError for unknown service' do
|
|
199
|
+
expect { described_class.get_contentstack_endpoint(region: 'na', service: 'unknownService') }
|
|
200
|
+
.to raise_error(ArgumentError, 'Service "unknownService" not found for region "na"')
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
it 'raises ArgumentError for valid region but unknown service' do
|
|
204
|
+
expect { described_class.get_contentstack_endpoint(region: 'eu', service: 'nonExistentService') }
|
|
205
|
+
.to raise_error(ArgumentError, /Service "nonExistentService" not found/)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# ── Additional service spot-checks ──────────────────────────────────────────
|
|
210
|
+
|
|
211
|
+
describe 'additional service endpoints' do
|
|
212
|
+
it 'resolves auth endpoint for NA' do
|
|
213
|
+
result = described_class.get_contentstack_endpoint(region: 'na', service: 'auth')
|
|
214
|
+
expect(result).to eq('https://auth-api.contentstack.com')
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
it 'resolves graphqlDelivery endpoint for EU' do
|
|
218
|
+
result = described_class.get_contentstack_endpoint(region: 'eu', service: 'graphqlDelivery')
|
|
219
|
+
expect(result).to eq('https://eu-graphql.contentstack.com')
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
it 'resolves preview endpoint for azure-na' do
|
|
223
|
+
result = described_class.get_contentstack_endpoint(region: 'azure-na', service: 'preview')
|
|
224
|
+
expect(result).to eq('https://azure-na-rest-preview.contentstack.com')
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
it 'resolves application endpoint for gcp-eu' do
|
|
228
|
+
result = described_class.get_contentstack_endpoint(region: 'gcp-eu', service: 'application')
|
|
229
|
+
expect(result).to eq('https://gcp-eu-app.contentstack.com')
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# ── Utils proxy ────────────────────────────────────────────────────────────────
|
|
235
|
+
|
|
236
|
+
RSpec.describe ContentstackUtils do
|
|
237
|
+
before(:each) do
|
|
238
|
+
ContentstackUtils::Endpoint.reset_cache
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
describe '.get_contentstack_endpoint' do
|
|
242
|
+
it 'returns same value as Endpoint.get_contentstack_endpoint for default args' do
|
|
243
|
+
expect(described_class.get_contentstack_endpoint)
|
|
244
|
+
.to eq(ContentstackUtils::Endpoint.get_contentstack_endpoint)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
it 'proxy returns contentDelivery for NA' do
|
|
248
|
+
result = described_class.get_contentstack_endpoint(region: 'na', service: 'contentDelivery')
|
|
249
|
+
expect(result).to eq('https://cdn.contentstack.io')
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it 'proxy respects omit_https option' do
|
|
253
|
+
result = described_class.get_contentstack_endpoint(region: 'na', service: 'contentDelivery', omit_https: true)
|
|
254
|
+
expect(result).to eq('cdn.contentstack.io')
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
it 'proxy returns full endpoints map when no service given' do
|
|
258
|
+
result = described_class.get_contentstack_endpoint(region: 'eu')
|
|
259
|
+
expect(result).to be_a(Hash)
|
|
260
|
+
expect(result['contentManagement']).to eq('https://eu-api.contentstack.com')
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
it 'proxy raises ArgumentError for invalid region' do
|
|
264
|
+
expect { described_class.get_contentstack_endpoint(region: 'bad-region') }
|
|
265
|
+
.to raise_error(ArgumentError, /Invalid region/)
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: contentstack_utils
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Contentstack
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-06-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -34,22 +34,22 @@ dependencies:
|
|
|
34
34
|
name: nokogiri
|
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
|
-
- - "
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '1.13'
|
|
40
|
-
- - "<"
|
|
37
|
+
- - "~>"
|
|
41
38
|
- !ruby/object:Gem::Version
|
|
42
39
|
version: '1.19'
|
|
40
|
+
- - ">="
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: 1.19.2
|
|
43
43
|
type: :runtime
|
|
44
44
|
prerelease: false
|
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
|
46
46
|
requirements:
|
|
47
|
-
- - "
|
|
48
|
-
- !ruby/object:Gem::Version
|
|
49
|
-
version: '1.13'
|
|
50
|
-
- - "<"
|
|
47
|
+
- - "~>"
|
|
51
48
|
- !ruby/object:Gem::Version
|
|
52
49
|
version: '1.19'
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: 1.19.2
|
|
53
53
|
- !ruby/object:Gem::Dependency
|
|
54
54
|
name: rake
|
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -110,16 +110,16 @@ dependencies:
|
|
|
110
110
|
name: yard
|
|
111
111
|
requirement: !ruby/object:Gem::Requirement
|
|
112
112
|
requirements:
|
|
113
|
-
- - "
|
|
113
|
+
- - ">="
|
|
114
114
|
- !ruby/object:Gem::Version
|
|
115
|
-
version: 0.9.
|
|
115
|
+
version: 0.9.44
|
|
116
116
|
type: :development
|
|
117
117
|
prerelease: false
|
|
118
118
|
version_requirements: !ruby/object:Gem::Requirement
|
|
119
119
|
requirements:
|
|
120
|
-
- - "
|
|
120
|
+
- - ">="
|
|
121
121
|
- !ruby/object:Gem::Version
|
|
122
|
-
version: 0.9.
|
|
122
|
+
version: 0.9.44
|
|
123
123
|
description: Contentstack Ruby client for the Content Delivery API
|
|
124
124
|
email:
|
|
125
125
|
- support@contentstack.com
|
|
@@ -128,7 +128,8 @@ extensions: []
|
|
|
128
128
|
extra_rdoc_files: []
|
|
129
129
|
files:
|
|
130
130
|
- ".cursor/rules/README.md"
|
|
131
|
-
- ".github/workflows/
|
|
131
|
+
- ".github/workflows/back-merge-pr.yml"
|
|
132
|
+
- ".github/workflows/check-version-bump.yml"
|
|
132
133
|
- ".github/workflows/codeql-analysis.yml"
|
|
133
134
|
- ".github/workflows/issues-jira.yml"
|
|
134
135
|
- ".github/workflows/policy-scan.yml"
|
|
@@ -149,6 +150,7 @@ files:
|
|
|
149
150
|
- SECURITY.md
|
|
150
151
|
- contentstack_utils.gemspec
|
|
151
152
|
- lib/contentstack_utils.rb
|
|
153
|
+
- lib/contentstack_utils/endpoint.rb
|
|
152
154
|
- lib/contentstack_utils/interface/renderable.rb
|
|
153
155
|
- lib/contentstack_utils/model/metadata.rb
|
|
154
156
|
- lib/contentstack_utils/model/options.rb
|
|
@@ -162,6 +164,7 @@ files:
|
|
|
162
164
|
- skills/framework/SKILL.md
|
|
163
165
|
- skills/ruby-style/SKILL.md
|
|
164
166
|
- skills/testing/SKILL.md
|
|
167
|
+
- spec/lib/endpoint_spec.rb
|
|
165
168
|
- spec/lib/model/metadata_spec.rb
|
|
166
169
|
- spec/lib/model/option_spec.rb
|
|
167
170
|
- spec/lib/utils_spec.rb
|
|
@@ -190,11 +193,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
190
193
|
- !ruby/object:Gem::Version
|
|
191
194
|
version: '0'
|
|
192
195
|
requirements: []
|
|
193
|
-
rubygems_version: 3.
|
|
196
|
+
rubygems_version: 3.3.27
|
|
194
197
|
signing_key:
|
|
195
198
|
specification_version: 4
|
|
196
199
|
summary: Contentstack Ruby Utils for
|
|
197
200
|
test_files:
|
|
201
|
+
- spec/lib/endpoint_spec.rb
|
|
198
202
|
- spec/lib/model/metadata_spec.rb
|
|
199
203
|
- spec/lib/model/option_spec.rb
|
|
200
204
|
- spec/lib/utils_spec.rb
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
name: 'Check Branch'
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
|
|
6
|
-
jobs:
|
|
7
|
-
check_branch:
|
|
8
|
-
runs-on: ubuntu-latest
|
|
9
|
-
steps:
|
|
10
|
-
- name: Comment PR
|
|
11
|
-
if: github.base_ref == 'master' && github.head_ref != 'staging'
|
|
12
|
-
uses: thollander/actions-comment-pull-request@v2
|
|
13
|
-
with:
|
|
14
|
-
message: |
|
|
15
|
-
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 next branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch.
|
|
16
|
-
- name: Check branch
|
|
17
|
-
if: github.base_ref == 'master' && github.head_ref != 'staging'
|
|
18
|
-
run: |
|
|
19
|
-
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 next branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch."
|
|
20
|
-
exit 1
|