Skip to content

Commit da3b0ef

Browse files
authored
Merge branch 'shashjar/make-organization-trace-item-stats-api-endpoint-generic-over-trace-item-type' into shashjar/issue-feed-search-eap-parse-search-filters-into-query-string
2 parents c584fcf + 2d13606 commit da3b0ef

File tree

762 files changed

+21346
-32551
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

762 files changed

+21346
-32551
lines changed

.agents/skills/sentry-security/references/serializer-patterns.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ class IssueAlertRuleSerializer(serializers.Serializer):
4040
1. If org has `allow_joinleave` flag → any team is allowed (user could join anyway)
4141
2. If user has `team:admin` scope → any team is allowed
4242
3. If user is a member of the target team → allowed
43-
4. If user is a member of the current owner's team → allowed (can reassign from their team)
44-
5. Otherwise → `ValidationError("You can only assign teams you are a member of")`
43+
4. Otherwise → `ValidationError("You can only assign teams you are a member of")`
4544

4645
### What to look for
4746

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ pyproject.toml @getsentry/owners-pytho
172172
vercel.json @getsentry/owners-js-build
173173
/.github/workflows/frontend.yml @getsentry/owners-js-build
174174
/.github/file-filters.yml @getsentry/owners-js-build
175-
babel.config.* @getsentry/owners-js-build
176175
build-utils/ @getsentry/owners-js-build
177176
eslint.config.ts @getsentry/owners-js-build
178177
jest-balance.json @getsentry/owners-js-build
@@ -356,6 +355,7 @@ tests/sentry/api/endpoints/test_organization_attribute_mappings.py @get
356355
/static/app/components/arithmeticBuilder/ @getsentry/data-browsing
357356

358357
/static/app/components/charts/ @getsentry/data-browsing
358+
/static/app/chartcuterie/timeseries.tsx @getsentry/data-browsing
359359

360360
/static/app/views/insights/ @getsentry/dashboards
361361

.github/dependabot.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ updates:
1515
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#groups
1616
groups:
1717
# The name of the group, it will be used in PR titles and branch
18-
babel-dependencies:
18+
swc-dependencies:
1919
patterns:
20-
- '@babel/*'
20+
- '@swc/*'
2121
sentry-dependencies:
2222
patterns:
2323
- '@sentry/core'

.github/file-filters.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
sentry_frontend_workflow_file: &sentry_frontend_workflow_file
44
- added|modified: '.github/workflows/frontend.yml'
55

6+
sentry_frontend_snapshots_workflow_file: &sentry_frontend_snapshots_workflow_file
7+
- added|modified: '.github/workflows/frontend-snapshots.yml'
8+
69
# Provides list of changed files to test (jest)
710
# getsentry/sentry does not use the list directly, instead we shard tests inside jest.config.js
811
testable_modified: &testable_modified
@@ -30,6 +33,7 @@ typecheckable_rules_changed: &typecheckable_rules_changed
3033
# Trigger to apply the 'Scope: Frontend' label to PRs
3134
frontend_all: &frontend_all
3235
- *sentry_frontend_workflow_file
36+
- *sentry_frontend_snapshots_workflow_file
3337
- added|modified: '**/*.{ts,tsx,js,jsx,mjs}'
3438
- added|modified: 'static/**/*.{less,json,yml,md,mdx}'
3539
- added|modified: '{vercel,tsconfig,biome,package}.json'

.github/workflows/acceptance.yml

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ jobs:
6363
# XXX: MATRIX_INSTANCE_TOTAL must match the matrix size (5 for backend changes, 10 for frontend-only)
6464
MATRIX_INSTANCE_TOTAL: ${{ needs.files-changed.outputs.backend_all == 'true' && '5' || '10' }}
6565
TEST_GROUP_STRATEGY: roundrobin
66+
PYTHONHASHSEED: '0'
67+
XDIST_PER_WORKER_SNUBA: '1'
68+
XDIST_WORKERS: '2'
6669

6770
steps:
6871
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
@@ -74,6 +77,13 @@ jobs:
7477
with:
7578
mode: acceptance-ci
7679

80+
- name: Start Snuba bootstrap
81+
if: env.XDIST_PER_WORKER_SNUBA == '1'
82+
run: |
83+
# Start in background early so it overlaps with webpack and sentry env setup.
84+
# The script polls for ClickHouse readiness itself.
85+
python3 ./.github/actions/setup-devservices/bootstrap-snuba.py &
86+
7787
- name: Step configurations
7888
id: config
7989
run: |
@@ -111,8 +121,20 @@ jobs:
111121
sentry init
112122
./.github/actions/setup-devservices/wait.sh
113123
124+
- name: Wait for Snuba bootstrap
125+
if: env.XDIST_PER_WORKER_SNUBA == '1'
126+
run: |
127+
timeout 600 bash -c 'until [ -f /tmp/snuba-bootstrap-exit ]; do sleep 2; done' ||
128+
{ echo "::error::Timed out waiting for Snuba bootstrap after 600s"; exit 1; }
129+
rc=$(</tmp/snuba-bootstrap-exit)
130+
[ "$rc" -eq 0 ] || { echo "::error::Snuba per-worker bootstrap failed"; exit "$rc"; }
131+
114132
- name: Run acceptance tests (#${{ steps.setup.outputs.matrix-instance-number }} of ${{ steps.setup.outputs.matrix-instance-total }})
115-
run: make run-acceptance
133+
run: |
134+
export PYTEST_ADDOPTS="$PYTEST_ADDOPTS -n ${XDIST_WORKERS} --dist=loadfile"
135+
timeout 1200 make run-acceptance || rc=$?
136+
[ "${rc:-0}" -ne 124 ] || echo "::error::Test run timed out after 20 minutes (possible xdist hang)"
137+
exit "${rc:-0}"
116138
117139
- name: Inspect failure
118140
if: failure()
@@ -126,6 +148,13 @@ jobs:
126148
devservices logs
127149
fi
128150
151+
if [ "${XDIST_PER_WORKER_SNUBA}" = "1" ]; then
152+
for i in $(seq 0 $(( ${XDIST_WORKERS} - 1 ))); do
153+
echo "--- snuba-gw${i} logs ---"
154+
docker logs "snuba-gw${i}" 2>&1 | tail -30 || true
155+
done
156+
fi
157+
129158
- name: Collect test data
130159
uses: ./.github/actions/collect-test-data
131160
if: ${{ !cancelled() }}

.github/workflows/frontend-snapshots.yml

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -69,37 +69,19 @@ jobs:
6969

7070
- name: Install sentry-cli
7171
if: ${{ !cancelled() }}
72-
run: curl -sL https://sentry.io/get-cli/ | SENTRY_CLI_VERSION=3.3.4 sh
72+
run: curl -sL https://sentry.io/get-cli/ | SENTRY_CLI_VERSION=3.3.5 sh
7373

7474
- name: Upload snapshots
7575
id: upload
7676
if: ${{ !cancelled() }}
7777
env:
7878
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_SNAPSHOTS_AUTH_TOKEN }}
79-
run: |
80-
ARGS=(
81-
--log-level=debug
82-
--auth-token "${{ secrets.SENTRY_SNAPSHOTS_AUTH_TOKEN }}"
83-
build snapshots "${{ env.SNAPSHOT_OUTPUT_DIR }}"
84-
--app-id sentry-frontend
85-
--project sentry-frontend
86-
--head-sha "${{ github.event.pull_request.head.sha || github.sha }}"
87-
--vcs-provider github
88-
--head-repo-name "${{ github.repository }}"
89-
)
90-
91-
# PR-only flags: base-sha, base-ref, base-repo-name, head-ref, pr-number
92-
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
93-
ARGS+=(
94-
--base-sha "${{ github.event.pull_request.base.sha }}"
95-
--base-repo-name "${{ github.repository }}"
96-
--head-ref "${{ github.head_ref }}"
97-
--base-ref "${{ github.base_ref }}"
98-
--pr-number "${{ github.event.number }}"
99-
)
100-
fi
101-
102-
sentry-cli "${ARGS[@]}"
79+
run: >
80+
sentry-cli
81+
--log-level=debug
82+
build snapshots "${{ env.SNAPSHOT_OUTPUT_DIR }}"
83+
--app-id sentry-frontend
84+
--project sentry-frontend
10385
10486
- name: Report upload failure to Sentry
10587
if: ${{ failure() && steps.upload.outcome == 'failure' }}

.github/workflows/frontend.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,17 @@ jobs:
131131

132132
- uses: ./.github/actions/setup-node-pnpm
133133

134+
- name: jest transform cache
135+
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
136+
with:
137+
path: |
138+
.cache/jest
139+
~/.cache/swc
140+
key: jest-cache-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'jest.config.ts') }}-${{ matrix.instance }}
141+
restore-keys: |
142+
jest-cache-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'jest.config.ts') }}-
143+
jest-cache-${{ runner.os }}-
144+
134145
- name: Download jest-balance.json
135146
id: download-artifact
136147
uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v11

.github/workflows/scripts/compute-sentry-selected-tests.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@
8686
re.compile(r"^tests/(acceptance|apidocs|js|tools)/"),
8787
]
8888

89+
# Tests that should always be run even if not explicitly selected.
90+
ALWAYS_RUN_TESTS: set[str] = {
91+
"tests/sentry/taskworker/test_config.py",
92+
}
93+
8994

9095
def _is_test(path: str) -> bool:
9196
return any(path.startswith(d) for d in TEST_DIRS)
@@ -225,6 +230,9 @@ def main() -> int:
225230
print(f"Including {len(existing_changed)} directly changed test files")
226231
affected_test_files.update(existing_changed)
227232

233+
# Always run these tests
234+
affected_test_files.update(ALWAYS_RUN_TESTS)
235+
228236
# Filter to sentry tests only (drop any getsentry tests from coverage)
229237
affected_test_files = {f for f in affected_test_files if _is_test(f)}
230238

.github/workflows/scripts/test_compute_sentry_selected_tests.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
sys.modules["compute_sentry_selected_tests"] = _mod
2020
_spec.loader.exec_module(_mod)
2121

22-
from compute_sentry_selected_tests import _query_coverage, main
22+
from compute_sentry_selected_tests import ALWAYS_RUN_TESTS, _query_coverage, main
2323

2424

2525
def _create_coverage_db(path: str, file_to_contexts: dict[str, list[str]]) -> None:
@@ -178,8 +178,9 @@ def test_selective_returns_matched_tests(self, tmp_path):
178178

179179
gh = gh_output.read_text()
180180
assert "has-selected-tests=true" in gh
181-
assert "test-count=1" in gh
182-
assert output.read_text().strip() == "tests/sentry/test_org.py"
181+
assert f"test-count={1 + len(ALWAYS_RUN_TESTS)}" in gh
182+
expected_output = sorted({"tests/sentry/test_org.py"} | ALWAYS_RUN_TESTS)
183+
assert output.read_text().splitlines() == expected_output
183184

184185
def test_getsentry_tests_filtered_out(self, tmp_path):
185186
"""Coverage may return getsentry tests — they should be filtered."""
@@ -211,8 +212,9 @@ def test_getsentry_tests_filtered_out(self, tmp_path):
211212
{"GITHUB_OUTPUT": str(gh_output)},
212213
)
213214

214-
assert "test-count=1" in gh_output.read_text()
215-
assert output.read_text().strip() == "tests/sentry/test_org.py"
215+
assert f"test-count={1 + len(ALWAYS_RUN_TESTS)}" in gh_output.read_text()
216+
expected_output = sorted({"tests/sentry/test_org.py"} | ALWAYS_RUN_TESTS)
217+
assert output.read_text().splitlines() == expected_output
216218

217219
def test_changed_test_file_included(self, tmp_path):
218220
db_path = tmp_path / "coverage.db"
@@ -236,7 +238,7 @@ def test_changed_test_file_included(self, tmp_path):
236238

237239
gh = gh_output.read_text()
238240
assert "has-selected-tests=true" in gh
239-
assert "test-count=1" in gh
241+
assert f"test-count={1 + len(ALWAYS_RUN_TESTS)}" in gh
240242

241243
def test_excluded_test_dirs_skipped(self, tmp_path):
242244
"""Tests in acceptance/apidocs/js/tools should not be selected."""
@@ -257,10 +259,10 @@ def test_excluded_test_dirs_skipped(self, tmp_path):
257259
{"GITHUB_OUTPUT": str(gh_output)},
258260
)
259261

260-
assert "test-count=0" in gh_output.read_text()
262+
assert f"test-count={len(ALWAYS_RUN_TESTS)}" in gh_output.read_text()
261263

262-
def test_zero_tests_signals_selective_applied(self, tmp_path):
263-
"""0 tests after filtering should signal 'run nothing', not full suite."""
264+
def test_zero_coverage_matches_still_runs_always_run_tests(self, tmp_path):
265+
"""No coverage matches should still run ALWAYS_RUN_TESTS, not the full suite."""
264266
db_path = tmp_path / "coverage.db"
265267
_create_coverage_db(str(db_path), {})
266268
output = tmp_path / "output.txt"
@@ -282,8 +284,8 @@ def test_zero_tests_signals_selective_applied(self, tmp_path):
282284

283285
gh = gh_output.read_text()
284286
assert "has-selected-tests=true" in gh
285-
assert "test-count=0" in gh
286-
assert output.read_text() == ""
287+
assert f"test-count={len(ALWAYS_RUN_TESTS)}" in gh
288+
assert set(output.read_text().splitlines()) == ALWAYS_RUN_TESTS
287289

288290
def test_renamed_file_queries_old_path(self, tmp_path):
289291
"""When a file is renamed, the old path should be queried against the coverage DB."""
@@ -319,8 +321,9 @@ def test_renamed_file_queries_old_path(self, tmp_path):
319321

320322
gh = gh_output.read_text()
321323
assert "has-selected-tests=true" in gh
322-
assert "test-count=1" in gh
323-
assert output.read_text().strip() == "tests/sentry/test_old_name.py"
324+
assert f"test-count={1 + len(ALWAYS_RUN_TESTS)}" in gh
325+
expected_output = sorted({"tests/sentry/test_old_name.py"} | ALWAYS_RUN_TESTS)
326+
assert output.read_text().splitlines() == expected_output
324327

325328
def test_renamed_file_without_previous_misses_coverage(self, tmp_path):
326329
"""Without --previous-filenames, a renamed file gets no coverage hits."""
@@ -349,7 +352,7 @@ def test_renamed_file_without_previous_misses_coverage(self, tmp_path):
349352

350353
gh = gh_output.read_text()
351354
assert "has-selected-tests=true" in gh
352-
assert "test-count=0" in gh
355+
assert f"test-count={len(ALWAYS_RUN_TESTS)}" in gh
353356

354357
def test_missing_db_returns_error(self):
355358
ret = _run(["--coverage-db", "/nonexistent/coverage.db", "--changed-files", "foo.py"])

.vercelignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
!src/sentry/locale/**
99
!build-utils
1010
!build-utils/**
11-
!babel.config.js
1211
!jest.config.js
1312
!now.json
1413
!package.json

0 commit comments

Comments
 (0)