Skip to content

Commit e34048b

Browse files
authored
Merge branch 'master' into snigdha/fix-ios-notif
2 parents 8dd02f8 + d6e07c6 commit e34048b

File tree

1,060 files changed

+15779
-49376
lines changed

Some content is hidden

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

1,060 files changed

+15779
-49376
lines changed

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,8 @@ tests/sentry/api/endpoints/test_organization_dashboard_widget_details.py @ge
523523
/static/app/views/settings/dynamicSampling/ @getsentry/telemetry-experience
524524
/static/app/views/onboarding* @getsentry/telemetry-experience
525525
/static/app/views/projectInstall/ @getsentry/telemetry-experience
526+
/static/app/views/insights/agentMonitoring/ @getsentry/telemetry-experience
527+
/static/app/views/insights/pages/platform/ @getsentry/telemetry-experience
526528
## End of Telemetry Experience
527529

528530

.pre-commit-config.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,14 @@ repos:
143143
|static/app/utils/profiling/profile/formats/typescript/trace\.json
144144
)$
145145
146+
- id: knip
147+
name: knip
148+
language: system
149+
files: \.(ts|js|tsx|jsx|mjs)$
150+
pass_filenames: false
151+
stages: [pre-push]
152+
entry: bash -c 'if [ -n "${SENTRY_KNIP_PRE_PUSH:-}" ]; then exec ./node_modules/.bin/knip; fi' --
153+
146154
- repo: https://github.com/pre-commit/pygrep-hooks
147155
rev: v1.10.0
148156
hooks:

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ test-cli: create-db
100100
cd test_cli && sentry init test_conf
101101
cd test_cli && sentry --config=test_conf help
102102
cd test_cli && sentry --config=test_conf upgrade --traceback --noinput
103-
cd test_cli && sentry --config=test_conf export
103+
cd test_cli && sentry --config=test_conf export --help
104104
rm -r test_cli
105105
@echo ""
106106

bin/load-integration-data

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/usr/bin/env python
2+
from sentry.runner import configure
3+
4+
configure()
5+
6+
import argparse
7+
8+
import click
9+
from django.core import serializers
10+
from django.db import IntegrityError, router
11+
12+
from sentry.integrations.models.integration import Integration
13+
from sentry.integrations.models.organization_integration import OrganizationIntegration
14+
from sentry.users.models.identity import Identity, IdentityProvider
15+
from sentry.utils.db import atomic_transaction
16+
17+
# The order in which models should be loaded to respect foreign key dependencies.
18+
MODEL_LOAD_ORDER = [
19+
"sentry.identityprovider",
20+
"sentry.integration",
21+
"sentry.identity", # Depends on sentry.identityprovider
22+
"sentry.organizationintegration", # Depends on sentry.integration (and sentry.organization)
23+
]
24+
25+
26+
def load_data(input_file, org_id):
27+
"""
28+
Loads data from a JSON file and saves it to the database.
29+
Assumes that PKs from the file should be preserved.
30+
"""
31+
click.echo(f"Reading serialized data from {input_file}...")
32+
with open(input_file) as f:
33+
serialized_data = f.read()
34+
35+
if not serialized_data.strip() or serialized_data.strip() == "[]":
36+
click.echo("Input file is empty or contains no data. Nothing to load.")
37+
return
38+
39+
click.echo("Deserializing objects...")
40+
try:
41+
deserialized_objects = list(serializers.deserialize("json", serialized_data))
42+
except Exception as e:
43+
click.echo(f"Error during deserialization: {e}")
44+
click.echo(
45+
"Please ensure the input file is a valid JSON dump created by the save_integration_data.py script."
46+
)
47+
return
48+
49+
if not deserialized_objects:
50+
click.echo("No objects were deserialized from the file.")
51+
return
52+
53+
click.echo(f"Deserialized {len(deserialized_objects)} objects.")
54+
55+
# Sort deserialized objects based on MODEL_LOAD_ORDER to handle dependencies.
56+
# Objects not in MODEL_LOAD_ORDER will be placed at the end.
57+
def get_sort_key(d_obj):
58+
model_key = f"{d_obj.object._meta.app_label}.{d_obj.object._meta.model_name}"
59+
try:
60+
return MODEL_LOAD_ORDER.index(model_key)
61+
except ValueError:
62+
return len(MODEL_LOAD_ORDER) # Put unknown models at the end
63+
64+
sorted_deserialized_objects = sorted(deserialized_objects, key=get_sort_key)
65+
66+
saved_count = 0
67+
skipped_count = 0
68+
error_count = 0
69+
70+
parsed_org_id = None
71+
if org_id:
72+
try:
73+
parsed_org_id = int(org_id)
74+
click.echo(
75+
f"Will update OrganizationIntegration objects to organization_id: {parsed_org_id}"
76+
)
77+
except ValueError:
78+
click.echo(
79+
f"Warning: Invalid org_id '{org_id}'. It will be ignored. Please provide a valid integer."
80+
)
81+
parsed_org_id = None
82+
83+
click.echo("Attempting to save objects to the database...")
84+
with atomic_transaction(
85+
using=(
86+
router.db_for_write(Integration),
87+
router.db_for_write(OrganizationIntegration),
88+
router.db_for_write(Identity),
89+
router.db_for_write(IdentityProvider),
90+
)
91+
):
92+
for deserialized_object in sorted_deserialized_objects:
93+
model_name = deserialized_object.object._meta.object_name
94+
pk = deserialized_object.object.pk
95+
96+
# If org_id is provided, update OrganizationIntegration's organization_id
97+
if parsed_org_id is not None and isinstance(
98+
deserialized_object.object, OrganizationIntegration
99+
):
100+
click.echo(
101+
f" Updating organization_id for {model_name} (PK: {pk}) to {parsed_org_id}"
102+
)
103+
deserialized_object.object.organization_id = parsed_org_id
104+
105+
try:
106+
# The deserialized_object.save() method handles saving the object
107+
# and its many-to-many data (if any). It attempts to use the PK
108+
# from the serialized data.
109+
deserialized_object.save()
110+
saved_count += 1
111+
click.echo(f" Saved: {model_name} (PK: {pk})")
112+
except IntegrityError as e:
113+
# This can occur due to PK conflict, unique constraint violation,
114+
# or a non-existent foreign key (e.g., if a referenced User or Organization
115+
# doesn't exist in the target DB).
116+
skipped_count += 1
117+
click.echo(f" Skipped: {model_name} (PK: {pk}) due to IntegrityError: {e}")
118+
except Exception as e:
119+
# Catch other potential errors during save.
120+
error_count += 1
121+
click.echo(f" Error saving: {model_name} (PK: {pk}): {e}")
122+
# Depending on severity, you might want to re-raise to stop the transaction.
123+
# For now, we'll log and continue.
124+
125+
click.echo("\nLoad process completed.")
126+
click.echo(f" Successfully saved: {saved_count} objects.")
127+
click.echo(f" Skipped (IntegrityError): {skipped_count} objects.")
128+
click.echo(f" Errors (Other): {error_count} objects.")
129+
if skipped_count > 0 or error_count > 0:
130+
click.echo(
131+
"Please check skipped/error messages. This might indicate that the target database was not clean,"
132+
)
133+
click.echo("or that required related objects (like Organizations or Users) were missing.")
134+
135+
136+
if __name__ == "__main__":
137+
parser = argparse.ArgumentParser(
138+
description="Load Sentry integration-related models from a JSON file into the database."
139+
)
140+
parser.add_argument(
141+
"--input-file",
142+
required=True,
143+
help="Path to the input JSON file containing the data to load.",
144+
)
145+
parser.add_argument(
146+
"--org-id",
147+
required=False,
148+
help="The organization ID to save integration data for.",
149+
)
150+
args = parser.parse_args()
151+
152+
load_data(args.input_file, args.org_id)

bin/save-integration-data

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env python
2+
from sentry.runner import configure
3+
4+
configure()
5+
6+
import argparse
7+
8+
import click
9+
from django.core import serializers
10+
11+
from sentry.integrations.models import Integration, OrganizationIntegration
12+
from sentry.users.models.identity import Identity, IdentityProvider
13+
14+
MODELS_TO_SERIALIZE = [
15+
IdentityProvider, # Has no FKs to other serialized models
16+
Integration, # Has no FKs to other serialized models
17+
Identity, # Depends on IdentityProvider
18+
OrganizationIntegration, # Depends on Integration
19+
]
20+
21+
22+
def save_data(output_file):
23+
"""
24+
Collects data from specified models and serializes it to a JSON file.
25+
"""
26+
all_objects_to_serialize = []
27+
click.echo("Collecting data from models...")
28+
for model_cls in MODELS_TO_SERIALIZE:
29+
model_name = f"{model_cls._meta.app_label}.{model_cls._meta.model_name}"
30+
click.echo(f" Fetching from {model_name}...")
31+
# Order by PK for consistent output, though serializer might reorder.
32+
# Convert queryset to list to avoid issues with extending during iteration if any.
33+
objects = list(model_cls.objects.order_by("pk").all())
34+
all_objects_to_serialize.extend(objects)
35+
click.echo(f" Found {len(objects)} objects.")
36+
37+
if not all_objects_to_serialize:
38+
click.echo("No objects found to serialize.")
39+
serialized_data = "[]"
40+
else:
41+
click.echo(f"\nSerializing {len(all_objects_to_serialize)} objects in total...")
42+
serialized_data = serializers.serialize("json", all_objects_to_serialize, indent=2)
43+
44+
click.echo(f"Writing serialized data to {output_file}...")
45+
with open(output_file, "w") as f:
46+
f.write(serialized_data)
47+
click.echo(f"Successfully saved data to {output_file}")
48+
49+
50+
if __name__ == "__main__":
51+
parser = argparse.ArgumentParser(
52+
description="Save Sentry integration-related models to a JSON file."
53+
)
54+
parser.add_argument(
55+
"--output-file",
56+
required=True,
57+
help="Path to the output JSON file where data will be saved.",
58+
)
59+
args = parser.parse_args()
60+
61+
save_data(args.output_file)

config/build-chartcuterie.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import fs from 'node:fs/promises';
66
import path from 'node:path';
77
import {fileURLToPath} from 'node:url';
88

9-
// @ts-expect-error need to switch tsconfig to use module: esnext or es2020
109
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
1110
const workspaceRoot = path.resolve(scriptDir, '..');
1211
const packageJsonPath = path.join(workspaceRoot, 'package.json');

config/tsconfig.base.json

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
//
1515
// [0]: https://babeljs.io/docs/en/babel-preset-typescript
1616
// [1]: https://node.green
17-
"module": "commonjs",
17+
"module": "preserve",
1818
"target": "ES2022",
19-
"moduleResolution": "node",
19+
"moduleResolution": "bundler",
2020

2121
// We add esnext to lib to pull in types for all newer ECMAScript features
2222
"lib": ["esnext", "dom", "dom.iterable"],
@@ -124,6 +124,13 @@
124124
"include": ["../static/app", "../static/gsApp", "../tests/js"],
125125
"exclude": ["../node_modules", "../**/*.benchmark.ts"],
126126
"ts-node": {
127-
"transpileOnly": true
127+
"transpileOnly": true,
128+
"compilerOptions": {
129+
// TODO: We should be able to use "node16" on next major version of jest
130+
// https://github.com/jestjs/jest/pull/14739
131+
"module": "commonjs",
132+
// TODO: node10 will be deprecated in typescript 6.0
133+
"moduleResolution": "node10"
134+
}
128135
}
129136
}

eslint.config.mjs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ export default typescript.config([
169169
// https://typescript-eslint.io/packages/parser/#projectservice
170170
// `projectService` is recommended, but slower, with our current tsconfig files.
171171
projectService: true,
172-
// @ts-expect-error TS1343: The import.meta meta-property is only allowed when the --module option is es2020, es2022, esnext, system, node16, or nodenext
173172
tsconfigRootDir: import.meta.dirname,
174173
},
175174
},

0 commit comments

Comments
 (0)