mirror of
https://github.com/apache/superset.git
synced 2026-06-10 10:09:14 +00:00
Compare commits
2 Commits
enxdev/cha
...
memory_lea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
793a075915 | ||
|
|
64d25c85f7 |
17
.asf.yaml
17
.asf.yaml
@@ -24,9 +24,7 @@ notifications:
|
||||
discussions: notifications@superset.apache.org
|
||||
|
||||
github:
|
||||
pull_requests:
|
||||
del_branch_on_merge: true
|
||||
allow_update_branch: true
|
||||
del_branch_on_merge: true
|
||||
description: "Apache Superset is a Data Visualization and Data Exploration Platform"
|
||||
homepage: https://superset.apache.org/
|
||||
labels:
|
||||
@@ -77,17 +75,22 @@ github:
|
||||
# combination here.
|
||||
contexts:
|
||||
- lint-check
|
||||
- cypress-matrix-required
|
||||
- cypress-matrix (0, chrome)
|
||||
- cypress-matrix (1, chrome)
|
||||
- cypress-matrix (2, chrome)
|
||||
- cypress-matrix (3, chrome)
|
||||
- cypress-matrix (4, chrome)
|
||||
- cypress-matrix (5, chrome)
|
||||
- dependency-review
|
||||
- frontend-build
|
||||
- playwright-tests-required
|
||||
- pre-commit (current)
|
||||
- pre-commit (previous)
|
||||
- test-mysql
|
||||
- test-postgres-required
|
||||
- test-postgres (current)
|
||||
- test-postgres-hive
|
||||
- test-postgres-presto
|
||||
- test-sqlite
|
||||
- unit-tests-required
|
||||
- unit-tests (current)
|
||||
|
||||
required_pull_request_reviews:
|
||||
dismiss_stale_reviews: false
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# JavaScript to TypeScript Migration Command
|
||||
|
||||
## Usage
|
||||
```
|
||||
/js-to-ts <core-filename>
|
||||
```
|
||||
- `<core-filename>` - Path to CORE file relative to `superset-frontend/` (e.g., `src/utils/common.js`, `src/middleware/loggerMiddleware.js`)
|
||||
|
||||
## Agent Instructions
|
||||
**See:** [../projects/js-to-ts/AGENT.md](../projects/js-to-ts/AGENT.md) for complete migration guide.
|
||||
@@ -1,684 +0,0 @@
|
||||
# JavaScript to TypeScript Migration Agent Guide
|
||||
|
||||
**Complete technical reference for converting JavaScript/JSX files to TypeScript/TSX in Apache Superset frontend.**
|
||||
|
||||
**Agent Role:** Atomic migration unit - migrate the core file + ALL related tests/mocks as one cohesive unit. Use `git mv` to preserve history, NO `git commit`. NO global import changes. Report results upon completion.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Migration Principles
|
||||
|
||||
1. **Atomic migration units** - Core file + all related tests/mocks migrate together
|
||||
2. **Zero `any` types** - Use proper TypeScript throughout
|
||||
3. **Leverage existing types** - Reuse established definitions
|
||||
4. **Type inheritance** - Derivatives extend base component types
|
||||
5. **Strategic placement** - File types for maximum discoverability
|
||||
6. **Surgical improvements** - Enhance existing types during migration
|
||||
|
||||
---
|
||||
|
||||
## Step 0: Dependency Check (MANDATORY)
|
||||
|
||||
**Command:**
|
||||
```bash
|
||||
grep -E "from '\.\./.*\.jsx?'|from '\./.*\.jsx?'|from 'src/.*\.jsx?'" superset-frontend/{filename}
|
||||
```
|
||||
|
||||
**Decision:**
|
||||
- ✅ No matches → Proceed with atomic migration (core + tests + mocks)
|
||||
- ❌ Matches found → EXIT with dependency report (see format below)
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Identify Related Files (REQUIRED)
|
||||
|
||||
**Atomic Migration Scope:**
|
||||
For core file `src/utils/example.js`, also migrate:
|
||||
- `src/utils/example.test.js` / `src/utils/example.test.jsx`
|
||||
- `src/utils/example.spec.js` / `src/utils/example.spec.jsx`
|
||||
- `src/utils/__mocks__/example.js`
|
||||
- Any other related test/mock files found by pattern matching
|
||||
|
||||
**Find all related test and mock files:**
|
||||
```bash
|
||||
# Pattern-based search for related files
|
||||
basename=$(basename {filename} .js)
|
||||
dirname=$(dirname superset-frontend/{filename})
|
||||
|
||||
# Find test files
|
||||
find "$dirname" -name "${basename}.test.js" -o -name "${basename}.test.jsx"
|
||||
find "$dirname" -name "${basename}.spec.js" -o -name "${basename}.spec.jsx"
|
||||
|
||||
# Find mock files
|
||||
find "$dirname" -name "__mocks__/${basename}.js"
|
||||
find "$dirname" -name "${basename}.mock.js"
|
||||
```
|
||||
|
||||
**Migration Requirement:** All discovered related files MUST be migrated together as one atomic unit.
|
||||
|
||||
**Test File Creation:** If NO test files exist for the core file, CREATE a minimal test file using the following pattern:
|
||||
- Location: Same directory as core file
|
||||
- Name: `{basename}.test.ts` (e.g., `DebouncedMessageQueue.test.ts`)
|
||||
- Content: Basic test structure importing and testing the main functionality
|
||||
- Use proper TypeScript types in test file
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Type Reference Map
|
||||
|
||||
### From `@superset-ui/core`
|
||||
```typescript
|
||||
// Data & Query
|
||||
QueryFormData, QueryData, JsonObject, AnnotationData, AdhocMetric
|
||||
LatestQueryFormData, GenericDataType, DatasourceType, ExtraFormData
|
||||
DataMaskStateWithId, NativeFilterScope, NativeFiltersState, NativeFilterTarget
|
||||
|
||||
// UI & Theme
|
||||
FeatureFlagMap, LanguagePack, ColorSchemeConfig, SequentialSchemeConfig
|
||||
```
|
||||
|
||||
### From `@superset-ui/chart-controls`
|
||||
```typescript
|
||||
Dataset, ColumnMeta, ControlStateMapping
|
||||
```
|
||||
|
||||
### From Local Types (`src/types/`)
|
||||
```typescript
|
||||
// Authentication
|
||||
User, UserWithPermissionsAndRoles, BootstrapUser, PermissionsAndRoles
|
||||
|
||||
// Dashboard
|
||||
Dashboard, DashboardState, DashboardInfo, DashboardLayout, LayoutItem
|
||||
ComponentType, ChartConfiguration, ActiveFilters
|
||||
|
||||
// Charts
|
||||
Chart, ChartState, ChartStatus, ChartLinkedDashboard, Slice, SaveActionType
|
||||
|
||||
// Data
|
||||
Datasource, Database, Owner, Role
|
||||
|
||||
// UI Components
|
||||
TagType, FavoriteStatus, Filter, ImportResourceName
|
||||
```
|
||||
|
||||
### From Domain Types
|
||||
```typescript
|
||||
// src/dashboard/types.ts
|
||||
RootState, ChartsState, DatasourcesState, FilterBarOrientation
|
||||
ChartCrossFiltersConfig, ActiveTabs, MenuKeys
|
||||
|
||||
// src/explore/types.ts
|
||||
ExplorePageInitialData, ExplorePageState, ExploreResponsePayload, OptionSortType
|
||||
|
||||
// src/SqlLab/types.ts
|
||||
[SQL Lab specific types]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Type Organization Strategy
|
||||
|
||||
### Type Placement Hierarchy
|
||||
|
||||
1. **Component-Colocated** (90% of cases)
|
||||
```typescript
|
||||
// Same file as component
|
||||
interface MyComponentProps {
|
||||
title: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
```
|
||||
|
||||
2. **Feature-Shared**
|
||||
```typescript
|
||||
// src/[domain]/components/[Feature]/types.ts
|
||||
export interface FilterConfiguration {
|
||||
filterId: string;
|
||||
targets: NativeFilterTarget[];
|
||||
}
|
||||
```
|
||||
|
||||
3. **Domain-Wide**
|
||||
```typescript
|
||||
// src/[domain]/types.ts
|
||||
export interface ExploreFormData extends QueryFormData {
|
||||
viz_type: string;
|
||||
}
|
||||
```
|
||||
|
||||
4. **Global**
|
||||
```typescript
|
||||
// src/types/[TypeName].ts
|
||||
export interface ApiResponse<T> {
|
||||
result: T;
|
||||
count?: number;
|
||||
}
|
||||
```
|
||||
|
||||
### Type Discovery Commands
|
||||
```bash
|
||||
# Search existing types before creating
|
||||
find superset-frontend/src -name "types.ts" -exec grep -l "[TypeConcept]" {} \;
|
||||
grep -r "interface.*Props\|type.*Props" superset-frontend/src/
|
||||
```
|
||||
|
||||
### Derivative Component Patterns
|
||||
|
||||
**Rule:** Components that extend others should extend their type interfaces.
|
||||
|
||||
```typescript
|
||||
// ✅ Base component type
|
||||
interface SelectProps {
|
||||
value: string | number;
|
||||
options: SelectOption[];
|
||||
onChange: (value: string | number) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
// ✅ Derivative extends base
|
||||
interface ChartSelectProps extends SelectProps {
|
||||
charts: Chart[];
|
||||
onChartSelect: (chart: Chart) => void;
|
||||
}
|
||||
|
||||
// ✅ Derivative with modified props
|
||||
interface DatabaseSelectProps extends Omit<SelectProps, 'value' | 'onChange'> {
|
||||
value: number; // Narrowed type
|
||||
onChange: (databaseId: number) => void; // Specific signature
|
||||
}
|
||||
```
|
||||
|
||||
**Common Patterns:**
|
||||
- **Extension:** `extends BaseProps` - adds new props
|
||||
- **Omission:** `Omit<BaseProps, 'prop'>` - removes props
|
||||
- **Modification:** `Omit<BaseProps, 'prop'> & { prop: NewType }` - changes prop type
|
||||
- **Restriction:** Override with narrower types (union → specific)
|
||||
|
||||
---
|
||||
|
||||
## 📋 Migration Recipe
|
||||
|
||||
### Step 2: File Conversion
|
||||
```bash
|
||||
# Use git mv to preserve history
|
||||
git mv component.js component.ts
|
||||
git mv Component.jsx Component.tsx
|
||||
```
|
||||
|
||||
### Step 3: Import & Type Setup
|
||||
```typescript
|
||||
// Import order (enforced by linting)
|
||||
import { FC, ReactNode } from 'react';
|
||||
import { JsonObject, QueryFormData } from '@superset-ui/core';
|
||||
import { Dataset } from '@superset-ui/chart-controls';
|
||||
import type { Dashboard } from 'src/types/Dashboard';
|
||||
```
|
||||
|
||||
### Step 4: Function & Component Typing
|
||||
```typescript
|
||||
// Functions with proper parameter/return types
|
||||
export function processData(
|
||||
data: Dataset[],
|
||||
config: JsonObject
|
||||
): ProcessedData[] {
|
||||
// implementation
|
||||
}
|
||||
|
||||
// Component props with inheritance
|
||||
interface ComponentProps extends BaseProps {
|
||||
data: Chart[];
|
||||
onSelect: (id: number) => void;
|
||||
}
|
||||
|
||||
const Component: FC<ComponentProps> = ({ data, onSelect }) => {
|
||||
// implementation
|
||||
};
|
||||
```
|
||||
|
||||
### Step 5: State & Redux Typing
|
||||
```typescript
|
||||
// Hooks with specific types
|
||||
const [data, setData] = useState<Chart[]>([]);
|
||||
const [selected, setSelected] = useState<number | null>(null);
|
||||
|
||||
// Redux with existing RootState
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
charts: state.charts,
|
||||
user: state.user,
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Type Debugging Strategies (Real-World Learnings)
|
||||
|
||||
### The Evolution of Type Approaches
|
||||
When you hit type errors, follow this debugging evolution:
|
||||
|
||||
#### 1. ❌ Idealized Union Types (First Attempt)
|
||||
```typescript
|
||||
// Looks clean but doesn't match reality
|
||||
type DatasourceInput = Datasource | QueryEditor;
|
||||
```
|
||||
**Problem**: Real calling sites pass variations, not exact types.
|
||||
|
||||
#### 2. ❌ Overly Precise Types (Second Attempt)
|
||||
```typescript
|
||||
// Tried to match exact calling signatures
|
||||
type DatasourceInput =
|
||||
| IDatasource // From DatasourcePanel
|
||||
| (QueryEditor & { columns: ColumnMeta[] }); // From SaveQuery
|
||||
```
|
||||
**Problem**: Too rigid, doesn't handle legacy variations.
|
||||
|
||||
#### 3. ✅ Flexible Interface (Final Solution)
|
||||
```typescript
|
||||
// Captures what the function actually needs
|
||||
interface DatasourceInput {
|
||||
name?: string | null; // Allow null for compatibility
|
||||
datasource_name?: string | null; // Legacy variations
|
||||
columns?: any[]; // Multiple column types accepted
|
||||
database?: { id?: number };
|
||||
// ... other optional properties
|
||||
}
|
||||
```
|
||||
**Success**: Works with all calling sites, focuses on function needs.
|
||||
|
||||
### Type Debugging Process
|
||||
1. **Start with compilation errors** - they show exact mismatches
|
||||
2. **Examine actual usage** - look at calling sites, not idealized types
|
||||
3. **Build flexible interfaces** - capture what functions need, not rigid contracts
|
||||
4. **Iterate based on downstream validation** - let calling sites guide your types
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Anti-Patterns to Avoid
|
||||
|
||||
```typescript
|
||||
// ❌ Never use any
|
||||
const obj: any = {};
|
||||
|
||||
// ✅ Use proper types
|
||||
const obj: Record<string, JsonObject> = {};
|
||||
|
||||
// ❌ Don't recreate base component props
|
||||
interface ChartSelectProps {
|
||||
value: string; // Duplicated from SelectProps
|
||||
onChange: () => void; // Duplicated from SelectProps
|
||||
charts: Chart[]; // New prop
|
||||
}
|
||||
|
||||
// ✅ Inherit and extend
|
||||
interface ChartSelectProps extends SelectProps {
|
||||
charts: Chart[]; // Only new props
|
||||
}
|
||||
|
||||
// ❌ Don't create ad-hoc type variations
|
||||
interface UserInfo {
|
||||
name: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
// ✅ Extend existing types (DRY principle)
|
||||
import { User } from 'src/types/bootstrapTypes';
|
||||
type UserDisplayInfo = Pick<User, 'firstName' | 'lastName' | 'email'>;
|
||||
|
||||
// ❌ Don't create overly rigid unions
|
||||
type StrictInput = ExactTypeA | ExactTypeB;
|
||||
|
||||
// ✅ Create flexible interfaces for function parameters
|
||||
interface FlexibleInput {
|
||||
// Focus on what the function actually needs
|
||||
commonProperty: string;
|
||||
optionalVariations?: any; // Allow for legacy variations
|
||||
}
|
||||
```
|
||||
|
||||
## 📍 DRY Type Guidelines (WHERE TYPES BELONG)
|
||||
|
||||
### Type Placement Rules
|
||||
**CRITICAL**: Type variations must live close to where they belong, not scattered across files.
|
||||
|
||||
#### ✅ Proper Type Organization
|
||||
```typescript
|
||||
// ❌ Don't create one-off interfaces in utility files
|
||||
// src/utils/datasourceUtils.ts
|
||||
interface DatasourceInput { /* custom interface */ } // Wrong!
|
||||
|
||||
// ✅ Use existing types or extend them in their proper domain
|
||||
// src/utils/datasourceUtils.ts
|
||||
import { IDatasource } from 'src/explore/components/DatasourcePanel';
|
||||
import { QueryEditor } from 'src/SqlLab/types';
|
||||
|
||||
// Create flexible interface that references existing types
|
||||
interface FlexibleDatasourceInput {
|
||||
// Properties that actually exist across variations
|
||||
}
|
||||
```
|
||||
|
||||
#### Type Location Hierarchy
|
||||
1. **Domain Types**: `src/{domain}/types.ts` (dashboard, explore, SqlLab)
|
||||
2. **Component Types**: Co-located with components
|
||||
3. **Global Types**: `src/types/` directory
|
||||
4. **Utility Types**: Only when they truly don't belong elsewhere
|
||||
|
||||
#### ✅ DRY Type Patterns
|
||||
```typescript
|
||||
// ✅ Extend existing domain types
|
||||
interface SaveQueryData extends Pick<QueryEditor, 'sql' | 'dbId' | 'catalog'> {
|
||||
columns: ColumnMeta[]; // Add what's needed
|
||||
}
|
||||
|
||||
// ✅ Create flexible interfaces for cross-domain utilities
|
||||
interface CrossDomainInput {
|
||||
// Common properties that exist across different source types
|
||||
name?: string | null; // Accommodate legacy null values
|
||||
// Only include properties the function actually uses
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 PropTypes Auto-Generation (Elegant Approach)
|
||||
|
||||
**IMPORTANT**: Superset has `babel-plugin-typescript-to-proptypes` configured to automatically generate PropTypes from TypeScript interfaces. Use this instead of manual PropTypes duplication!
|
||||
|
||||
### ❌ Manual PropTypes Duplication (Avoid This)
|
||||
```typescript
|
||||
export interface MyComponentProps {
|
||||
title: string;
|
||||
count?: number;
|
||||
}
|
||||
|
||||
// 8+ lines of manual PropTypes duplication 😱
|
||||
const propTypes = PropTypes.shape({
|
||||
title: PropTypes.string.isRequired,
|
||||
count: PropTypes.number,
|
||||
});
|
||||
|
||||
export default propTypes;
|
||||
```
|
||||
|
||||
### ✅ Auto-Generated PropTypes (Use This)
|
||||
```typescript
|
||||
import { InferProps } from 'prop-types';
|
||||
|
||||
export interface MyComponentProps {
|
||||
title: string;
|
||||
count?: number;
|
||||
}
|
||||
|
||||
// Single validator function - babel plugin auto-generates PropTypes! ✨
|
||||
export default function MyComponentValidator(props: MyComponentProps) {
|
||||
return null; // PropTypes auto-assigned by babel-plugin-typescript-to-proptypes
|
||||
}
|
||||
|
||||
// Optional: For consumers needing PropTypes type inference
|
||||
export type MyComponentPropsInferred = InferProps<typeof MyComponentValidator>;
|
||||
```
|
||||
|
||||
### Migration Pattern for Type-Only Files
|
||||
|
||||
**When migrating type-only files with manual PropTypes:**
|
||||
|
||||
1. **Keep the TypeScript interfaces** (single source of truth)
|
||||
2. **Replace manual PropTypes** with validator function
|
||||
3. **Remove PropTypes imports** and manual shape definitions
|
||||
4. **Add InferProps import** if type inference needed
|
||||
|
||||
**Example Migration:**
|
||||
```typescript
|
||||
// Before: 25+ lines with manual PropTypes duplication
|
||||
export interface AdhocFilterType { /* ... */ }
|
||||
const adhocFilterTypePropTypes = PropTypes.oneOfType([...]);
|
||||
|
||||
// After: 3 lines with auto-generation
|
||||
export interface AdhocFilterType { /* ... */ }
|
||||
export default function AdhocFilterValidator(props: { filter: AdhocFilterType }) {
|
||||
return null; // Auto-generated PropTypes by babel plugin
|
||||
}
|
||||
```
|
||||
|
||||
### Component PropTypes Pattern
|
||||
|
||||
**For React components, the babel plugin works automatically:**
|
||||
|
||||
```typescript
|
||||
interface ComponentProps {
|
||||
title: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
const MyComponent: FC<ComponentProps> = ({ title, onClick }) => {
|
||||
// Component implementation
|
||||
};
|
||||
|
||||
// PropTypes automatically generated by babel plugin - no manual work needed!
|
||||
export default MyComponent;
|
||||
```
|
||||
|
||||
### Auto-Generation Benefits
|
||||
|
||||
- ✅ **Single source of truth**: TypeScript interfaces drive PropTypes
|
||||
- ✅ **No duplication**: Eliminate 15-20 lines of manual PropTypes code
|
||||
- ✅ **Automatic updates**: Changes to TypeScript automatically update PropTypes
|
||||
- ✅ **Type safety**: Compile-time checking ensures PropTypes match interfaces
|
||||
- ✅ **Backward compatibility**: Existing JavaScript components continue working
|
||||
|
||||
### Babel Plugin Configuration
|
||||
|
||||
The plugin is already configured in `babel.config.js`:
|
||||
```javascript
|
||||
['babel-plugin-typescript-to-proptypes', { loose: true }]
|
||||
```
|
||||
|
||||
**No additional setup required** - just use TypeScript interfaces and the plugin handles the rest!
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Test File Migration Patterns
|
||||
|
||||
### Test File Priority
|
||||
- **Always migrate test files** alongside production files
|
||||
- **Test files are often leaf nodes** - good starting candidates
|
||||
- **Create tests if missing** - Leverage new TypeScript types for better test coverage
|
||||
|
||||
### Test-Specific Type Patterns
|
||||
```typescript
|
||||
// Mock interfaces for testing
|
||||
interface MockStore {
|
||||
getState: () => Partial<RootState>; // Partial allows minimal mocking
|
||||
}
|
||||
|
||||
// Type-safe mocking for complex objects
|
||||
const mockDashboardInfo: Partial<DashboardInfo> as DashboardInfo = {
|
||||
id: 123,
|
||||
json_metadata: '{}',
|
||||
};
|
||||
|
||||
// Sinon stub typing
|
||||
let postStub: sinon.SinonStub;
|
||||
beforeEach(() => {
|
||||
postStub = sinon.stub(SupersetClient, 'post');
|
||||
});
|
||||
|
||||
// Use stub reference instead of original method
|
||||
expect(postStub.callCount).toBe(1);
|
||||
expect(postStub.getCall(0).args[0].endpoint).toMatch('/api/');
|
||||
```
|
||||
|
||||
### Test Migration Recipe
|
||||
1. **Migrate production file first** (if both need migration)
|
||||
2. **Update test imports** to point to `.ts/.tsx` files
|
||||
3. **Add proper mock typing** using `Partial<T> as T` pattern
|
||||
4. **Fix stub typing** - Use stub references, not original methods
|
||||
5. **Verify all tests pass** with TypeScript compilation
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Type Conflict Resolution
|
||||
|
||||
### Multiple Type Definitions Issue
|
||||
**Problem**: Same type name defined in multiple files causes compilation errors.
|
||||
|
||||
**Example**: `DashboardInfo` defined in both:
|
||||
- `src/dashboard/reducers/types.ts` (minimal)
|
||||
- `src/dashboard/components/Header/types.ts` (different shape)
|
||||
- `src/dashboard/types.ts` (complete - used by RootState)
|
||||
|
||||
### Resolution Strategy
|
||||
1. **Identify the authoritative type**:
|
||||
```bash
|
||||
# Find which type is used by RootState/main interfaces
|
||||
grep -r "DashboardInfo" src/dashboard/types.ts
|
||||
```
|
||||
|
||||
2. **Use import from authoritative source**:
|
||||
```typescript
|
||||
// ✅ Import from main domain types
|
||||
import { RootState, DashboardInfo } from 'src/dashboard/types';
|
||||
|
||||
// ❌ Don't import from component-specific files
|
||||
import { DashboardInfo } from 'src/dashboard/components/Header/types';
|
||||
```
|
||||
|
||||
3. **Mock complex types in tests**:
|
||||
```typescript
|
||||
// For testing - provide minimal required fields
|
||||
const mockInfo: Partial<DashboardInfo> as DashboardInfo = {
|
||||
id: 123,
|
||||
json_metadata: '{}',
|
||||
// Only provide fields actually used in test
|
||||
};
|
||||
```
|
||||
|
||||
### Type Hierarchy Discovery Commands
|
||||
```bash
|
||||
# Find all definitions of a type
|
||||
grep -r "interface.*TypeName\|type.*TypeName" src/
|
||||
|
||||
# Find import usage patterns
|
||||
grep -r "import.*TypeName" src/
|
||||
|
||||
# Check what RootState uses
|
||||
grep -A 10 -B 10 "TypeName" src/*/types.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Agent Constraints (CRITICAL)
|
||||
|
||||
1. **Use git mv** - Run `git mv file.js file.ts` to preserve git history, but NO `git commit`
|
||||
2. **NO global import changes** - Don't update imports across codebase
|
||||
3. **Type files OK** - Can modify existing type files to improve/align types
|
||||
4. **Single-File TypeScript Validation** (CRITICAL) - tsc has known issues with multi-file compilation:
|
||||
- **Core Issue**: TypeScript's `tsc` has documented problems validating multiple files simultaneously in complex projects
|
||||
- **Solution**: ALWAYS validate files one at a time using individual `tsc` calls
|
||||
- **Command Pattern**: `cd superset-frontend && npx tscw --noEmit --allowJs --composite false --project tsconfig.json {single-file-path}`
|
||||
- **Why**: Multi-file validation can produce false positives, miss real errors, and conflict during parallel agent execution
|
||||
5. **Downstream Impact Validation** (CRITICAL) - Your migration affects calling sites:
|
||||
- **Find downstream files**: `find superset-frontend/src -name "*.tsx" -o -name "*.ts" | xargs grep -l "your-core-filename" 2>/dev/null || echo "No files found"`
|
||||
- **Validate each downstream file individually**: `cd superset-frontend && npx tscw --noEmit --allowJs --composite false --project tsconfig.json {each-downstream-file}`
|
||||
- **Fix type mismatches** you introduced in calling sites
|
||||
- **NEVER ignore downstream errors** - they indicate your types don't match reality
|
||||
6. **Avoid Project-Wide Validation During Migration**:
|
||||
- **NEVER use `npm run type`** during parallel agent execution - produces unreliable results
|
||||
- **Single-file validation is authoritative** - trust individual file checks over project-wide scans
|
||||
6. **ESLint validation** - Run `npm run eslint -- --fix {file}` for each migrated file to auto-fix formatting/linting issues
|
||||
6. Zero `any` types - use proper TypeScript types
|
||||
7. Search existing types before creating new ones
|
||||
8. Follow patterns from this guide
|
||||
|
||||
---
|
||||
|
||||
## Success Report Format
|
||||
|
||||
```
|
||||
SUCCESS: Atomic Migration of {core-filename}
|
||||
|
||||
## Files Migrated (Atomic Unit)
|
||||
- Core: {core-filename} → {core-filename.ts/tsx}
|
||||
- Tests: {list-of-test-files} → {list-of-test-files.ts/tsx} OR "CREATED: {basename}.test.ts"
|
||||
- Mocks: {list-of-mock-files} → {list-of-mock-files.ts}
|
||||
- Type files modified: {list-of-type-files}
|
||||
|
||||
## Types Created/Improved
|
||||
- {TypeName}: {location} ({scope}) - {rationale}
|
||||
- {ExistingType}: enhanced in {location} - {improvement-description}
|
||||
|
||||
## Documentation Recommendations
|
||||
- ADD_TO_DIRECTORY: {TypeName} - {reason}
|
||||
- NO_DOCUMENTATION: {TypeName} - {reason}
|
||||
|
||||
## Quality Validation
|
||||
- **Single-File TypeScript Validation**: ✅ PASS - Core files individually validated
|
||||
- Core file: `npx tscw --noEmit --allowJs --composite false --project tsconfig.json {core-file}`
|
||||
- Test files: `npx tscw --noEmit --allowJs --composite false --project tsconfig.json {test-file}` (if exists)
|
||||
- **Downstream Impact Check**: ✅ PASS - Found {N} files importing this module, all validate individually
|
||||
- Downstream files: {list-of-files-that-import-your-module}
|
||||
- Individual validation: `npx tscw --noEmit --allowJs --composite false --project tsconfig.json {each-downstream-file}`
|
||||
- **ESLint validation**: ✅ PASS (using `npm run eslint -- --fix {files}` to auto-fix formatting)
|
||||
- **Zero any types**: ✅ PASS
|
||||
- **Local imports resolved**: ✅ PASS
|
||||
- **Functionality preserved**: ✅ PASS
|
||||
- **Tests pass** (if test file): ✅ PASS
|
||||
- **Follow-up action required**: {YES/NO}
|
||||
|
||||
## Validation Strategy Notes
|
||||
- **Single-file approach used**: Avoided multi-file tsc validation due to known TypeScript compilation issues
|
||||
- **Project-wide validation skipped**: `npm run type` not used during parallel migration to prevent false positives
|
||||
|
||||
## Migration Learnings
|
||||
- Type conflicts encountered: {describe any multiple type definitions}
|
||||
- Mock patterns used: {describe test mocking approaches}
|
||||
- Import hierarchy decisions: {note authoritative type sources used}
|
||||
- PropTypes strategy: {AUTO_GENERATED via babel plugin | MANUAL_DUPLICATION_REMOVED | N/A}
|
||||
|
||||
## Improvement Suggestions for Documentation
|
||||
- AGENT.md enhancement: {suggest additions to migration guide}
|
||||
- Common pattern identified: {note reusable patterns for future migrations}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dependency Block Report Format
|
||||
|
||||
```
|
||||
DEPENDENCY_BLOCK: Cannot migrate {filename}
|
||||
|
||||
## Blocking Dependencies
|
||||
- {path}: {type} - {usage} - {priority}
|
||||
|
||||
## Impact Analysis
|
||||
- Estimated types: {number}
|
||||
- Expected locations: {list}
|
||||
- Cross-domain: {YES/NO}
|
||||
|
||||
## Recommended Order
|
||||
{ordered-list}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Quick Reference
|
||||
|
||||
**Type Utilities:**
|
||||
- `Record<K, V>` - Object with specific key/value types
|
||||
- `Partial<T>` - All properties optional
|
||||
- `Pick<T, K>` - Subset of properties
|
||||
- `Omit<T, K>` - Exclude specific properties
|
||||
- `NonNullable<T>` - Exclude null/undefined
|
||||
|
||||
**Event Types:**
|
||||
- `MouseEvent<HTMLButtonElement>`
|
||||
- `ChangeEvent<HTMLInputElement>`
|
||||
- `FormEvent<HTMLFormElement>`
|
||||
|
||||
**React Types:**
|
||||
- `FC<Props>` - Functional component
|
||||
- `ReactNode` - Any renderable content
|
||||
- `CSSProperties` - Style objects
|
||||
|
||||
---
|
||||
|
||||
**Remember:** Every type should add value and clarity. The goal is meaningful type safety that catches bugs and improves developer experience.
|
||||
@@ -1,199 +0,0 @@
|
||||
# JS-to-TS Coordinator Workflow
|
||||
|
||||
**Role:** Strategic migration coordination - select leaf-node files, trigger agents, review results, handle integration, manage dependencies.
|
||||
|
||||
---
|
||||
|
||||
## 1. Core File Selection Strategy
|
||||
|
||||
**Target ONLY Core Files**: Coordinators identify core files (production code), agents handle related tests/mocks atomically.
|
||||
|
||||
**File Analysis Commands**:
|
||||
```bash
|
||||
# Find CORE files with no JS/JSX dependencies (exclude tests/mocks) - SIZE PRIORITIZED
|
||||
find superset-frontend/src -name "*.js" -o -name "*.jsx" | grep -v "test\|spec\|mock" | xargs wc -l | sort -n | head -20
|
||||
|
||||
# Alternative: Get file sizes in lines with paths
|
||||
find superset-frontend/src -name "*.js" -o -name "*.jsx" | grep -v "test\|spec\|mock" | while read file; do
|
||||
lines=$(wc -l < "$file")
|
||||
echo "$lines $file"
|
||||
done | sort -n | head -20
|
||||
|
||||
# Check dependencies for core files only (start with smallest)
|
||||
for file in <core-files-sorted-by-size>; do
|
||||
echo "=== $file ($(wc -l < "$file") lines) ==="
|
||||
grep -E "from '\.\./.*\.jsx?'|from '\./.*\.jsx?'|from 'src/.*\.jsx?'" "$file" || echo "✅ LEAF CANDIDATE"
|
||||
done
|
||||
|
||||
# Identify heavily imported files (migrate last)
|
||||
grep -r "from.*utils/common" superset-frontend/src/ | wc -l
|
||||
|
||||
# Quick leaf analysis with size priority
|
||||
find superset-frontend/src -name "*.js" -o -name "*.jsx" | grep -v "test\|spec\|mock" | head -30 | while read file; do
|
||||
deps=$(grep -E "from '\.\./.*\.jsx?'|from '\./.*\.jsx?'|from 'src/.*\.jsx?'" "$file" | wc -l)
|
||||
lines=$(wc -l < "$file")
|
||||
if [ "$deps" -eq 0 ]; then
|
||||
echo "✅ LEAF: $lines lines - $file"
|
||||
fi
|
||||
done | sort -n
|
||||
```
|
||||
|
||||
**Priority Order** (Smallest files first for easier wins):
|
||||
1. **Small leaf files** (<50 lines) - No JS/JSX imports, quick TypeScript conversion
|
||||
2. **Medium leaf files** (50-200 lines) - Self-contained utilities and helpers
|
||||
3. **Small dependency files** (<100 lines) - Import only already-migrated files
|
||||
4. **Larger components** (200+ lines) - Complex but well-contained functionality
|
||||
5. **Core foundational files** (utils/common.js, controls.jsx) - migrate last regardless of size
|
||||
|
||||
**Size-First Benefits**:
|
||||
- Faster completion builds momentum
|
||||
- Earlier validation of migration patterns
|
||||
- Easier rollback if issues arise
|
||||
- Better success rate for agent learning
|
||||
|
||||
**Migration Unit**: Each agent call migrates:
|
||||
- 1 core file (primary target)
|
||||
- All related `*.test.js/jsx` files
|
||||
- All related `*.mock.js` files
|
||||
- All related `__mocks__/` files
|
||||
|
||||
---
|
||||
|
||||
## 2. Task Creation & Agent Control
|
||||
|
||||
### Task Triggering
|
||||
When triggering the `/js-to-ts` command:
|
||||
- **Task Title**: Use the core filename as the task title (e.g., "DebouncedMessageQueue.js migration", "hostNamesConfig.js migration")
|
||||
- **Task Description**: Include the full relative path to help agent locate the file
|
||||
- **Reference**: Point agent to [AGENT.md](./AGENT.md) for technical instructions
|
||||
|
||||
### Post-Processing Workflow
|
||||
After each agent completes:
|
||||
|
||||
1. **Review Agent Report**: Always read and analyze the complete agent report
|
||||
2. **Share Summary**: Provide user with key highlights from agent's work:
|
||||
- Files migrated (core + tests/mocks)
|
||||
- Types created or improved
|
||||
- Any validation issues or coordinator actions needed
|
||||
3. **Quality Assessment**: Evaluate agent's TypeScript implementation against criteria:
|
||||
- ✅ **Type Usage**: Proper types used, no `any` types
|
||||
- ✅ **Type Filing**: Types placed in correct hierarchy (component → feature → domain → global)
|
||||
- ✅ **Side Effects**: No unintended changes to other files
|
||||
- ✅ **Import Alignment**: Proper .ts/.tsx import extensions
|
||||
4. **Integration Decision**:
|
||||
- **COMMIT**: If agent work is complete and high quality
|
||||
- **FIX & COMMIT**: If minor issues need coordinator fixes
|
||||
- **ROLLBACK**: If major issues require complete rework
|
||||
5. **Next Action**: Ask user preference - commit this work or trigger next migration
|
||||
|
||||
---
|
||||
|
||||
## 3. Integration Decision Framework
|
||||
|
||||
**Automatic Integration** ✅:
|
||||
- `npm run type` passes without errors
|
||||
- Agent created clean TypeScript with proper types
|
||||
- Types appropriately filed in hierarchy
|
||||
|
||||
**Coordinator Integration** (Fix Side-Effects) 🔧:
|
||||
- `npm run type` fails BUT agent's work is high quality
|
||||
- Good type usage, proper patterns, well-organized
|
||||
- Side-effects are manageable TypeScript compilation errors
|
||||
- **Coordinator Action**: Integrate the change, then fix global compilation issues
|
||||
|
||||
**Rollback Only** ❌:
|
||||
- Agent introduced `any` types or poor type choices
|
||||
- Types poorly organized or conflicting with existing patterns
|
||||
- Fundamental approach issues requiring complete rework
|
||||
|
||||
**Integration Process**:
|
||||
1. **Review**: Agent already used `git mv` to preserve history
|
||||
2. **Fix Side-Effects**: Update dependent files with proper import extensions
|
||||
3. **Resolve Types**: Fix any cascading type issues across codebase
|
||||
4. **Validate**: Ensure `npm run type` passes after fixes
|
||||
|
||||
---
|
||||
|
||||
## 4. Common Integration Patterns
|
||||
|
||||
**Common Side-Effects (Expect These)**:
|
||||
- **Type import conflicts**: Multiple definitions of same type name
|
||||
- **Mock object typing**: Tests need complete type satisfaction
|
||||
- **Stub method references**: Use stub vars instead of original methods
|
||||
|
||||
**Coordinator Fixes (Standard Process)**:
|
||||
1. **Import Resolution**:
|
||||
```bash
|
||||
# Find authoritative type source
|
||||
grep -r "TypeName" src/*/types.ts
|
||||
# Import from domain types (src/dashboard/types.ts) not component types
|
||||
```
|
||||
|
||||
2. **Test Mock Completion**:
|
||||
```typescript
|
||||
// Use Partial<T> as T pattern for minimal mocking
|
||||
const mockDashboard: Partial<DashboardInfo> as DashboardInfo = {
|
||||
id: 123,
|
||||
json_metadata: '{}',
|
||||
};
|
||||
```
|
||||
|
||||
3. **Stub Reference Fixes**:
|
||||
```typescript
|
||||
// ✅ Use stub variable
|
||||
expect(postStub.callCount).toBe(1);
|
||||
// ❌ Don't use original method
|
||||
expect(SupersetClient.post.callCount).toBe(1);
|
||||
```
|
||||
|
||||
4. **Validation Commands**:
|
||||
```bash
|
||||
npm run type # TypeScript compilation
|
||||
npm test -- filename # Test functionality
|
||||
git status # Should show rename, not add/delete
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. File Categories for Planning
|
||||
|
||||
### Leaf Files (Start Here)
|
||||
**Self-contained files with minimal JS/JSX dependencies**:
|
||||
- Test files (80 files) - Usually only import the file being tested
|
||||
- Utility files without internal dependencies
|
||||
- Components importing only external libraries
|
||||
|
||||
### Heavily Imported Files (Migrate Last)
|
||||
**Core files that many others depend on**:
|
||||
- `utils/common.js` - Core utility functions
|
||||
- `utils/reducerUtils.js` - Redux helpers
|
||||
- `@superset-ui/core` equivalent files
|
||||
- Major state management files (`explore/store.js`, `dashboard/actions/`)
|
||||
|
||||
### Complex Components (Middle Priority)
|
||||
**Large files requiring careful type analysis**:
|
||||
- `components/Datasource/DatasourceEditor.jsx` (1,809 lines)
|
||||
- `explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx` (1,031 lines)
|
||||
- `explore/components/ExploreViewContainer/index.jsx` (911 lines)
|
||||
|
||||
---
|
||||
|
||||
## 6. Success Metrics & Continuous Improvement
|
||||
|
||||
**Per-File Gates**:
|
||||
- ✅ `npm run type` passes after each migration
|
||||
- ✅ Zero `any` types introduced
|
||||
- ✅ All imports properly typed
|
||||
- ✅ Types filed in correct hierarchy
|
||||
|
||||
**Linear Scheduling**:
|
||||
When agents report `DEPENDENCY_BLOCK`:
|
||||
- Queue dependencies in linear order
|
||||
- Process one file at a time to avoid conflicts
|
||||
- Handle cascading type changes between files
|
||||
|
||||
**After Each Migration**:
|
||||
1. **Update guides** with new patterns discovered
|
||||
2. **Document coordinator fixes** that become common
|
||||
3. **Enhance agent instructions** based on recurring issues
|
||||
4. **Track success metrics** - automatic vs coordinator integration rates
|
||||
@@ -1,76 +0,0 @@
|
||||
# JavaScript to TypeScript Migration Project
|
||||
|
||||
Progressive migration of 219 JS/JSX files to TypeScript in Apache Superset frontend.
|
||||
|
||||
## 📁 Project Documentation
|
||||
|
||||
- **[AGENT.md](./AGENT.md)** - Complete technical migration guide for agents (includes type reference, patterns, validation)
|
||||
- **[COORDINATOR.md](./COORDINATOR.md)** - Strategic workflow for coordinators (file selection, task management, integration)
|
||||
|
||||
## 🎯 Quick Start
|
||||
|
||||
**For Agents:** Read [AGENT.md](./AGENT.md) for complete migration instructions
|
||||
**For Coordinators:** Read [COORDINATOR.md](./COORDINATOR.md) for workflow and [AGENT.md](./AGENT.md) for supervision
|
||||
|
||||
**Command:** `/js-to-ts <filename>` - See [../../commands/js-to-ts.md](../../commands/js-to-ts.md)
|
||||
|
||||
## 📊 Migration Progress
|
||||
|
||||
**Scope**: 219 files total (112 JS + 107 JSX)
|
||||
- Production files: 139 (63%)
|
||||
- Test files: 80 (37%)
|
||||
|
||||
**Strategy**: Leaf-first migration with dependency-aware coordination
|
||||
|
||||
### Completed Migrations ✅
|
||||
|
||||
1. **roundDecimal** - `plugins/legacy-plugin-chart-map-box/src/utils/roundDecimal.js`
|
||||
- Migrated core + test files
|
||||
- Added proper TypeScript function signature with optional precision parameter
|
||||
- All tests pass
|
||||
|
||||
2. **timeGrainSqlaAnimationOverrides** - `src/explore/controlPanels/timeGrainSqlaAnimationOverrides.js`
|
||||
- Migrated to TypeScript with ControlPanelState and Dataset types
|
||||
- Added TimeGrainOverrideState interface for return type
|
||||
- Used type guards for safe property access
|
||||
|
||||
3. **DebouncedMessageQueue** - `src/utils/DebouncedMessageQueue.js`
|
||||
- Migrated to TypeScript with proper generics
|
||||
- Created DebouncedMessageQueueOptions interface
|
||||
- **CREATED test file** with 4 comprehensive test cases
|
||||
- Excellent class property typing with private/readonly modifiers
|
||||
|
||||
**Files Migrated**: 3/219 (1.4%)
|
||||
**Tests Created**: 2 (roundDecimal had existing, DebouncedMessageQueue created)
|
||||
|
||||
### Next Candidates (Leaf Nodes) 🎯
|
||||
|
||||
**Identified leaf files with no JS/JSX dependencies:**
|
||||
- `src/utils/hostNamesConfig.js` - Domain configuration utility
|
||||
- `src/explore/controlPanels/Separator.js` - Control panel configuration
|
||||
- `src/middleware/loggerMiddleware.js` - Logging middleware
|
||||
|
||||
**Migration Quality**: All completed migrations have:
|
||||
- ✅ Zero `any` types
|
||||
- ✅ Proper TypeScript compilation
|
||||
- ✅ ESLint validation passed
|
||||
- ✅ Test coverage (created where missing)
|
||||
|
||||
---
|
||||
|
||||
## 📈 Success Metrics
|
||||
|
||||
**Per-File Gates**:
|
||||
- ✅ `npm run type` passes after each migration
|
||||
- ✅ Zero `any` types introduced
|
||||
- ✅ All imports properly typed
|
||||
- ✅ Types filed in correct hierarchy
|
||||
|
||||
**Overall Progress**:
|
||||
- **Automatic Integration Rate**: 100% (3/3 migrations required no coordinator fixes)
|
||||
- **Test Coverage**: Improved (1 new test file created)
|
||||
- **Type Safety**: Enhanced with proper interfaces and generics
|
||||
|
||||
---
|
||||
|
||||
*This is a claudette-managed progressive refactor. All documentation and coordination resources are organized under `.claude/projects/js-to-ts/`*
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "jq -r '.tool_input.command // \"\"' | grep -qE '^git commit' && cd \"$CLAUDE_PROJECT_DIR\" && echo '🔍 Running pre-commit before commit...' && pre-commit run || true"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3,3 +3,14 @@
|
||||
For complete documentation on using GitHub Codespaces with Apache Superset, please see:
|
||||
|
||||
**[Setting up a Development Environment - GitHub Codespaces](https://superset.apache.org/docs/contributing/development#github-codespaces-cloud-development)**
|
||||
|
||||
## Pre-installed Development Environment
|
||||
|
||||
When you create a new Codespace from this repository, it automatically:
|
||||
|
||||
1. **Creates a Python virtual environment** using `uv venv`
|
||||
2. **Installs all development dependencies** via `uv pip install -r requirements/development.txt`
|
||||
3. **Sets up pre-commit hooks** with `pre-commit install`
|
||||
4. **Activates the virtual environment** automatically in all terminals
|
||||
|
||||
The virtual environment is located at `/workspaces/{repository-name}/.venv` and is automatically activated through environment variables set in the devcontainer configuration.
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
// Extend the base configuration
|
||||
"extends": "../devcontainer-base.json",
|
||||
|
||||
"name": "Apache Superset Development (Default)",
|
||||
|
||||
// Forward ports for development
|
||||
"forwardPorts": [9001],
|
||||
"portsAttributes": {
|
||||
"9001": {
|
||||
"label": "Superset (via Webpack Dev Server)",
|
||||
"onAutoForward": "notify",
|
||||
"visibility": "public"
|
||||
}
|
||||
},
|
||||
|
||||
// Auto-start Superset on Codespace resume
|
||||
"postStartCommand": ".devcontainer/start-superset.sh"
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"name": "Apache Superset Development",
|
||||
// Keep this in sync with the base image in Dockerfile (ARG PY_VER)
|
||||
// Using the same base as Dockerfile, but non-slim for dev tools
|
||||
"image": "python:3.11.13-bookworm",
|
||||
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/docker-in-docker:2": {
|
||||
"moby": true,
|
||||
"dockerDashComposeVersion": "v2"
|
||||
},
|
||||
"ghcr.io/devcontainers/features/node:1": {
|
||||
"version": "20"
|
||||
},
|
||||
"ghcr.io/devcontainers/features/git:1": {},
|
||||
"ghcr.io/devcontainers/features/common-utils:2": {
|
||||
"configureZshAsDefaultShell": true
|
||||
},
|
||||
"ghcr.io/devcontainers/features/sshd:1": {
|
||||
"version": "latest"
|
||||
}
|
||||
},
|
||||
|
||||
// Run commands after container is created
|
||||
"postCreateCommand": "chmod +x .devcontainer/setup-dev.sh && .devcontainer/setup-dev.sh",
|
||||
|
||||
// VS Code customizations
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"ms-python.python",
|
||||
"ms-python.vscode-pylance",
|
||||
"charliermarsh.ruff",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/docker-in-docker:2": {
|
||||
"moby": false,
|
||||
"moby": true,
|
||||
"dockerDashComposeVersion": "v2"
|
||||
},
|
||||
"ghcr.io/devcontainers/features/node:1": {
|
||||
|
||||
@@ -3,30 +3,76 @@
|
||||
|
||||
echo "🔧 Setting up Superset development environment..."
|
||||
|
||||
# The universal image has most tools, just need Superset-specific libs
|
||||
echo "📦 Installing Superset-specific dependencies..."
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
libsasl2-dev \
|
||||
libldap2-dev \
|
||||
libpq-dev \
|
||||
tmux \
|
||||
gh
|
||||
# System dependencies and uv are now pre-installed in the Docker image
|
||||
# This speeds up Codespace creation significantly!
|
||||
|
||||
# Install uv for fast Python package management
|
||||
echo "📦 Installing uv..."
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
# Create virtual environment using uv
|
||||
echo "🐍 Creating Python virtual environment..."
|
||||
if ! uv venv; then
|
||||
echo "❌ Failed to create virtual environment"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Add cargo/bin to PATH for uv
|
||||
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.bashrc
|
||||
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.zshrc
|
||||
# Install Python dependencies
|
||||
echo "📦 Installing Python dependencies..."
|
||||
if ! uv pip install -r requirements/development.txt; then
|
||||
echo "❌ Failed to install Python dependencies"
|
||||
echo "💡 You may need to run this manually after the Codespace starts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install pre-commit hooks
|
||||
echo "🪝 Installing pre-commit hooks..."
|
||||
if source .venv/bin/activate && pre-commit install; then
|
||||
echo "✅ Pre-commit hooks installed"
|
||||
else
|
||||
echo "⚠️ Pre-commit hooks installation failed (non-critical)"
|
||||
fi
|
||||
|
||||
# Install Claude Code CLI via npm
|
||||
echo "🤖 Installing Claude Code..."
|
||||
npm install -g @anthropic-ai/claude-code
|
||||
if npm install -g @anthropic-ai/claude-code; then
|
||||
echo "✅ Claude Code installed"
|
||||
else
|
||||
echo "⚠️ Claude Code installation failed (non-critical)"
|
||||
fi
|
||||
|
||||
# Make the start script executable
|
||||
chmod +x .devcontainer/start-superset.sh
|
||||
|
||||
# Add bashrc additions for automatic venv activation
|
||||
echo "🔧 Setting up automatic environment activation..."
|
||||
if [ -f ~/.bashrc ]; then
|
||||
# Check if we've already added our additions
|
||||
if ! grep -q "Superset Codespaces environment setup" ~/.bashrc; then
|
||||
echo "" >> ~/.bashrc
|
||||
cat .devcontainer/bashrc-additions >> ~/.bashrc
|
||||
echo "✅ Added automatic venv activation to ~/.bashrc"
|
||||
else
|
||||
echo "✅ Bashrc additions already present"
|
||||
fi
|
||||
else
|
||||
# Create bashrc if it doesn't exist
|
||||
cat .devcontainer/bashrc-additions > ~/.bashrc
|
||||
echo "✅ Created ~/.bashrc with automatic venv activation"
|
||||
fi
|
||||
|
||||
# Also add to zshrc since that's the default shell
|
||||
if [ -f ~/.zshrc ] || [ -n "$ZSH_VERSION" ]; then
|
||||
if ! grep -q "Superset Codespaces environment setup" ~/.zshrc; then
|
||||
echo "" >> ~/.zshrc
|
||||
cat .devcontainer/bashrc-additions >> ~/.zshrc
|
||||
echo "✅ Added automatic venv activation to ~/.zshrc"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "✅ Development environment setup complete!"
|
||||
echo "🚀 Run '.devcontainer/start-superset.sh' to start Superset"
|
||||
echo ""
|
||||
echo "📝 The virtual environment will be automatically activated in new terminals"
|
||||
echo ""
|
||||
echo "🔄 To activate in this terminal, run:"
|
||||
echo " source ~/.bashrc"
|
||||
echo ""
|
||||
echo "🚀 To start Superset:"
|
||||
echo " start-superset"
|
||||
echo ""
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#!/bin/bash
|
||||
# Startup script for Superset in Codespaces
|
||||
|
||||
# Log to a file for debugging
|
||||
LOG_FILE="/tmp/superset-startup.log"
|
||||
echo "[$(date)] Starting Superset startup script" >> "$LOG_FILE"
|
||||
echo "[$(date)] User: $(whoami), PWD: $(pwd)" >> "$LOG_FILE"
|
||||
|
||||
echo "🚀 Starting Superset in Codespaces..."
|
||||
echo "🌐 Frontend will be available at port 9001"
|
||||
|
||||
# Check if MCP is enabled
|
||||
if [ "$ENABLE_MCP" = "true" ]; then
|
||||
echo "🤖 MCP Service will be available at port 5008"
|
||||
fi
|
||||
|
||||
# Find the workspace directory (Codespaces clones as 'superset', not 'superset-2')
|
||||
WORKSPACE_DIR=$(find /workspaces -maxdepth 1 -name "superset*" -type d | head -1)
|
||||
if [ -n "$WORKSPACE_DIR" ]; then
|
||||
@@ -18,32 +18,71 @@ else
|
||||
echo "📁 Using current directory: $(pwd)"
|
||||
fi
|
||||
|
||||
# Check if docker is running
|
||||
if ! docker info > /dev/null 2>&1; then
|
||||
echo "⏳ Waiting for Docker to start..."
|
||||
sleep 5
|
||||
# Wait for Docker to be available
|
||||
echo "⏳ Waiting for Docker to start..."
|
||||
echo "[$(date)] Waiting for Docker..." >> "$LOG_FILE"
|
||||
max_attempts=30
|
||||
attempt=0
|
||||
while ! docker info > /dev/null 2>&1; do
|
||||
if [ $attempt -eq $max_attempts ]; then
|
||||
echo "❌ Docker failed to start after $max_attempts attempts"
|
||||
echo "[$(date)] Docker failed to start after $max_attempts attempts" >> "$LOG_FILE"
|
||||
echo "🔄 Please restart the Codespace or run this script manually later"
|
||||
exit 1
|
||||
fi
|
||||
echo " Attempt $((attempt + 1))/$max_attempts..."
|
||||
echo "[$(date)] Docker check attempt $((attempt + 1))/$max_attempts" >> "$LOG_FILE"
|
||||
sleep 2
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
echo "✅ Docker is ready!"
|
||||
echo "[$(date)] Docker is ready" >> "$LOG_FILE"
|
||||
|
||||
# Check if Superset containers are already running
|
||||
if docker ps | grep -q "superset"; then
|
||||
echo "✅ Superset containers are already running!"
|
||||
echo ""
|
||||
echo "🌐 To access Superset:"
|
||||
echo " 1. Click the 'Ports' tab at the bottom of VS Code"
|
||||
echo " 2. Find port 9001 and click the globe icon to open"
|
||||
echo " 3. Wait 10-20 minutes for initial startup"
|
||||
echo ""
|
||||
echo "📝 Login credentials: admin/admin"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Clean up any existing containers
|
||||
echo "🧹 Cleaning up existing containers..."
|
||||
docker-compose -f docker-compose-light.yml --profile mcp down
|
||||
docker-compose -f docker-compose-light.yml down
|
||||
|
||||
# Start services
|
||||
echo "🏗️ Building and starting services..."
|
||||
echo "🏗️ Starting Superset in background (daemon mode)..."
|
||||
echo ""
|
||||
echo "📝 Once started, login with:"
|
||||
echo " Username: admin"
|
||||
echo " Password: admin"
|
||||
echo ""
|
||||
echo "📋 Running in foreground with live logs (Ctrl+C to stop)..."
|
||||
|
||||
# Run docker-compose and capture exit code
|
||||
if [ "$ENABLE_MCP" = "true" ]; then
|
||||
echo "🤖 Starting with MCP Service enabled..."
|
||||
docker-compose -f docker-compose-light.yml --profile mcp up
|
||||
else
|
||||
docker-compose -f docker-compose-light.yml up
|
||||
fi
|
||||
# Start in detached mode
|
||||
docker-compose -f docker-compose-light.yml up -d
|
||||
|
||||
echo ""
|
||||
echo "✅ Docker Compose started successfully!"
|
||||
echo ""
|
||||
echo "📋 Important information:"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "⏱️ Initial startup takes 10-20 minutes"
|
||||
echo "🌐 Check the 'Ports' tab for your Superset URL (port 9001)"
|
||||
echo "👤 Login: admin / admin"
|
||||
echo ""
|
||||
echo "📊 Useful commands:"
|
||||
echo " docker-compose -f docker-compose-light.yml logs -f # Follow logs"
|
||||
echo " docker-compose -f docker-compose-light.yml ps # Check status"
|
||||
echo " docker-compose -f docker-compose-light.yml down # Stop services"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "💤 Keeping terminal open for 60 seconds to test persistence..."
|
||||
sleep 60
|
||||
echo "✅ Test complete - check if this terminal is still visible!"
|
||||
|
||||
# Show final status
|
||||
docker-compose -f docker-compose-light.yml ps
|
||||
EXIT_CODE=$?
|
||||
|
||||
# If it failed, provide helpful instructions
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
// Extend the base configuration
|
||||
"extends": "../devcontainer-base.json",
|
||||
|
||||
"name": "Apache Superset Development with MCP",
|
||||
|
||||
// Forward ports for development
|
||||
"forwardPorts": [9001, 5008],
|
||||
"portsAttributes": {
|
||||
"9001": {
|
||||
"label": "Superset (via Webpack Dev Server)",
|
||||
"onAutoForward": "notify",
|
||||
"visibility": "public"
|
||||
},
|
||||
"5008": {
|
||||
"label": "MCP Service (Model Context Protocol)",
|
||||
"onAutoForward": "notify",
|
||||
"visibility": "private"
|
||||
}
|
||||
},
|
||||
|
||||
// Auto-start Superset with MCP on Codespace resume
|
||||
"postStartCommand": "ENABLE_MCP=true .devcontainer/start-superset.sh",
|
||||
|
||||
// Environment variables
|
||||
"containerEnv": {
|
||||
"ENABLE_MCP": "true"
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# Auto-configure Docker Compose for multi-instance support
|
||||
# Requires direnv: https://direnv.net/
|
||||
#
|
||||
# Install: brew install direnv (or apt install direnv)
|
||||
# Setup: Add 'eval "$(direnv hook bash)"' to ~/.bashrc (or ~/.zshrc)
|
||||
# Allow: Run 'direnv allow' in this directory once
|
||||
|
||||
# Generate unique project name from directory
|
||||
export COMPOSE_PROJECT_NAME=$(basename "$PWD" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g')
|
||||
|
||||
# Find available ports sequentially to avoid collisions
|
||||
_is_free() { ! lsof -i ":$1" &>/dev/null 2>&1; }
|
||||
|
||||
_p=80; while ! _is_free $_p; do ((_p++)); done; export NGINX_PORT=$_p
|
||||
_p=8088; while ! _is_free $_p; do ((_p++)); done; export SUPERSET_PORT=$_p
|
||||
_p=9000; while ! _is_free $_p; do ((_p++)); done; export NODE_PORT=$_p
|
||||
_p=8080; while ! _is_free $_p || [ $_p -eq $NGINX_PORT ]; do ((_p++)); done; export WEBSOCKET_PORT=$_p
|
||||
_p=8081; while ! _is_free $_p || [ $_p -eq $WEBSOCKET_PORT ]; do ((_p++)); done; export CYPRESS_PORT=$_p
|
||||
_p=5432; while ! _is_free $_p; do ((_p++)); done; export DATABASE_PORT=$_p
|
||||
_p=6379; while ! _is_free $_p; do ((_p++)); done; export REDIS_PORT=$_p
|
||||
|
||||
unset _p _is_free
|
||||
|
||||
echo "🐳 Superset configured: http://localhost:$SUPERSET_PORT (dev: localhost:$NODE_PORT)"
|
||||
26
.github/CODEOWNERS
vendored
26
.github/CODEOWNERS
vendored
@@ -20,12 +20,7 @@
|
||||
|
||||
# Notify PMC members of changes to GitHub Actions
|
||||
|
||||
/.github/ @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @craig-rueda @kgabryje @dpgaspar @sadpandajoe @hainenber
|
||||
|
||||
# Notify PMC members of changes to CI-executed scripts (supply-chain risk:
|
||||
# scripts/ files run directly in CI workflows and can execute arbitrary code)
|
||||
|
||||
/scripts/ @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @craig-rueda @kgabryje @dpgaspar @sadpandajoe @hainenber
|
||||
/.github/ @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @craig-rueda @kgabryje @dpgaspar
|
||||
|
||||
# Notify PMC members of changes to required GitHub Actions
|
||||
|
||||
@@ -36,17 +31,12 @@
|
||||
**/*.geojson @villebro @rusackas
|
||||
/superset-frontend/plugins/legacy-plugin-chart-country-map/ @villebro @rusackas
|
||||
|
||||
# Notify translation maintainers of changes to translations
|
||||
|
||||
/superset/translations/ @sfirke @rusackas
|
||||
|
||||
# Notify PMC members of changes to extension-related files
|
||||
|
||||
/docs/developer_portal/extensions/ @michael-s-molina @villebro @rusackas
|
||||
/superset-core/ @michael-s-molina @villebro @geido @eschutho @rusackas @kgabryje
|
||||
/superset-extensions-cli/ @michael-s-molina @villebro @geido @eschutho @rusackas @kgabryje
|
||||
/superset/core/ @michael-s-molina @villebro @geido @eschutho @rusackas @kgabryje
|
||||
/superset/extensions/ @michael-s-molina @villebro @geido @eschutho @rusackas @kgabryje
|
||||
/superset-frontend/src/packages/superset-core/ @michael-s-molina @villebro @geido @eschutho @rusackas @kgabryje
|
||||
/superset-frontend/src/core/ @michael-s-molina @villebro @geido @eschutho @rusackas @kgabryje
|
||||
/superset-frontend/src/extensions/ @michael-s-molina @villebro @geido @eschutho @rusackas @kgabryje
|
||||
/superset-core/ @michael-s-molina @villebro
|
||||
/superset-extensions-cli/ @michael-s-molina @villebro
|
||||
/superset/core/ @michael-s-molina @villebro
|
||||
/superset/extensions/ @michael-s-molina @villebro
|
||||
/superset-frontend/src/packages/superset-core/ @michael-s-molina @villebro
|
||||
/superset-frontend/src/core/ @michael-s-molina @villebro
|
||||
/superset-frontend/src/extensions/ @michael-s-molina @villebro
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -41,8 +41,8 @@ body:
|
||||
label: Superset version
|
||||
options:
|
||||
- master / latest-dev
|
||||
- "6.0.0"
|
||||
- "5.0.0"
|
||||
- "4.1.3"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
|
||||
38
.github/SECURITY.md
vendored
Normal file
38
.github/SECURITY.md
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# Security Policy
|
||||
|
||||
This is a project of the [Apache Software Foundation](https://apache.org) and follows the
|
||||
ASF [vulnerability handling process](https://apache.org/security/#vulnerability-handling).
|
||||
|
||||
## Reporting Vulnerabilities
|
||||
|
||||
**⚠️ Please do not file GitHub issues for security vulnerabilities as they are public! ⚠️**
|
||||
|
||||
|
||||
Apache Software Foundation takes a rigorous standpoint in annihilating the security issues
|
||||
in its software projects. Apache Superset is highly sensitive and forthcoming to issues
|
||||
pertaining to its features and functionality.
|
||||
If you have any concern or believe you have found a vulnerability in Apache Superset,
|
||||
please get in touch with the Apache Superset Security Team privately at
|
||||
e-mail address [security@superset.apache.org](mailto:security@superset.apache.org).
|
||||
|
||||
More details can be found on the ASF website at
|
||||
[ASF vulnerability reporting process](https://apache.org/security/#reporting-a-vulnerability)
|
||||
|
||||
We kindly ask you to include the following information in your report:
|
||||
- Apache Superset version that you are using
|
||||
- A sanitized copy of your `superset_config.py` file or any config overrides
|
||||
- Detailed steps to reproduce the vulnerability
|
||||
|
||||
Note that Apache Superset is not responsible for any third-party dependencies that may
|
||||
have security issues. Any vulnerabilities found in third-party dependencies should be
|
||||
reported to the maintainers of those projects. Results from security scans of Apache
|
||||
Superset dependencies found on its official Docker image can be remediated at release time
|
||||
by extending the image itself.
|
||||
|
||||
**Your responsible disclosure and collaboration are invaluable.**
|
||||
|
||||
## Extra Information
|
||||
|
||||
- [Apache Superset documentation](https://superset.apache.org/docs/security)
|
||||
- [Common Vulnerabilities and Exposures by release](https://superset.apache.org/docs/security/cves)
|
||||
- [How Security Vulnerabilities are Reported & Handled in Apache Superset (Blog)](https://preset.io/blog/how-security-vulnerabilities-are-reported-and-handled-in-apache-superset/)
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
steps:
|
||||
- name: Check if the PR is a draft
|
||||
id: check-draft
|
||||
uses: actions/github-script@v8
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const isDraft = context.payload.pull_request.draft;
|
||||
|
||||
35
.github/actions/setup-backend/action.yml
vendored
35
.github/actions/setup-backend/action.yml
vendored
@@ -24,41 +24,32 @@ runs:
|
||||
- name: Interpret Python Version
|
||||
id: set-python-version
|
||||
shell: bash
|
||||
env:
|
||||
INPUT_PYTHON_VERSION: ${{ inputs.python-version }}
|
||||
run: |
|
||||
if [ "$INPUT_PYTHON_VERSION" = "current" ]; then
|
||||
RESOLVED_VERSION="3.11"
|
||||
elif [ "$INPUT_PYTHON_VERSION" = "next" ]; then
|
||||
if [ "${{ inputs.python-version }}" = "current" ]; then
|
||||
echo "PYTHON_VERSION=3.11" >> $GITHUB_ENV
|
||||
elif [ "${{ inputs.python-version }}" = "next" ]; then
|
||||
# currently disabled in GHA matrixes because of library compatibility issues
|
||||
RESOLVED_VERSION="3.12"
|
||||
elif [ "$INPUT_PYTHON_VERSION" = "previous" ]; then
|
||||
RESOLVED_VERSION="3.10"
|
||||
elif printf '%s' "$INPUT_PYTHON_VERSION" | grep -Eq '^[0-9]+\.[0-9]+(\.[0-9]+)?$'; then
|
||||
RESOLVED_VERSION="$INPUT_PYTHON_VERSION"
|
||||
echo "PYTHON_VERSION=3.12" >> $GITHUB_ENV
|
||||
elif [ "${{ inputs.python-version }}" = "previous" ]; then
|
||||
echo "PYTHON_VERSION=3.10" >> $GITHUB_ENV
|
||||
else
|
||||
echo "Invalid python-version: '$INPUT_PYTHON_VERSION'" >&2
|
||||
exit 1
|
||||
echo "PYTHON_VERSION=${{ inputs.python-version }}" >> $GITHUB_ENV
|
||||
fi
|
||||
echo "python-version=$RESOLVED_VERSION" >> "$GITHUB_OUTPUT"
|
||||
- name: Set up Python ${{ steps.set-python-version.outputs.python-version }}
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ steps.set-python-version.outputs.python-version }}
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
cache: ${{ inputs.cache }}
|
||||
- name: Install dependencies
|
||||
env:
|
||||
INPUT_INSTALL_SUPERSET: ${{ inputs.install-superset }}
|
||||
INPUT_REQUIREMENTS_TYPE: ${{ inputs.requirements-type }}
|
||||
run: |
|
||||
if [ "$INPUT_INSTALL_SUPERSET" = "true" ]; then
|
||||
if [ "${{ inputs.install-superset }}" = "true" ]; then
|
||||
sudo apt-get update && sudo apt-get -y install libldap2-dev libsasl2-dev
|
||||
|
||||
pip install --upgrade pip setuptools wheel uv
|
||||
|
||||
if [ "$INPUT_REQUIREMENTS_TYPE" = "dev" ]; then
|
||||
if [ "${{ inputs.requirements-type }}" = "dev" ]; then
|
||||
uv pip install --system -r requirements/development.txt
|
||||
elif [ "$INPUT_REQUIREMENTS_TYPE" = "base" ]; then
|
||||
elif [ "${{ inputs.requirements-type }}" = "base" ]; then
|
||||
uv pip install --system -r requirements/base.txt
|
||||
fi
|
||||
|
||||
|
||||
15
.github/actions/setup-docker/action.yml
vendored
15
.github/actions/setup-docker/action.yml
vendored
@@ -26,25 +26,16 @@ runs:
|
||||
|
||||
- name: Set up QEMU
|
||||
if: ${{ inputs.build == 'true' }}
|
||||
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
|
||||
with:
|
||||
# Pin the binfmt image to a specific QEMU release. The default
|
||||
# (`tonistiigi/binfmt:latest`) is a moving target, and drift across
|
||||
# QEMU's x86_64→aarch64 translator has been the proximate cause of
|
||||
# intermittent `exit code: 132` (SIGILL) failures during the arm64
|
||||
# leg of the multi-platform docker build — newer Node native modules
|
||||
# emit instructions QEMU's user-mode emulation occasionally drops on
|
||||
# the floor. Pinning a known-good release stabilises that path.
|
||||
image: tonistiigi/binfmt:qemu-v8.1.5
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
if: ${{ inputs.build == 'true' }}
|
||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Try to login to DockerHub
|
||||
if: ${{ inputs.login-to-dockerhub == 'true' }}
|
||||
continue-on-error: true
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ inputs.dockerhub-user }}
|
||||
password: ${{ inputs.dockerhub-token }}
|
||||
|
||||
5
.github/actions/setup-supersetbot/action.yml
vendored
5
.github/actions/setup-supersetbot/action.yml
vendored
@@ -10,7 +10,7 @@ runs:
|
||||
steps:
|
||||
|
||||
- name: Setup Node Env
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
@@ -21,9 +21,8 @@ runs:
|
||||
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
if: ${{ inputs.from-npm == 'false' }}
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
repository: apache-superset/supersetbot
|
||||
path: supersetbot
|
||||
|
||||
|
||||
2
.github/copilot-instructions.md
vendored
2
.github/copilot-instructions.md
vendored
@@ -1 +1 @@
|
||||
../AGENTS.md
|
||||
../LLMS.md
|
||||
258
.github/dependabot.yml
vendored
258
.github/dependabot.yml
vendored
@@ -1,403 +1,336 @@
|
||||
version: 2
|
||||
enable-beta-ecosystems: true
|
||||
updates:
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
ignore:
|
||||
# Ignore temporarily as release schedule is too mentally taxing for dep-handling maintainers
|
||||
# Additionally, very few PRs are reviewed by this action.
|
||||
- dependency-name: anthropics/claude-code-action
|
||||
schedule:
|
||||
interval: "daily"
|
||||
cooldown:
|
||||
default-days: 7
|
||||
interval: "monthly"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
ignore:
|
||||
# TODO: remove below entries until React >= 18.0.0
|
||||
# not until React >= 18.0.0
|
||||
- dependency-name: "storybook"
|
||||
update-types: ["version-update:semver-major", "version-update:semver-minor"]
|
||||
- dependency-name: "@storybook*"
|
||||
update-types: ["version-update:semver-major", "version-update:semver-minor"]
|
||||
- dependency-name: "eslint-plugin-storybook"
|
||||
- dependency-name: "react-error-boundary"
|
||||
- dependency-name: "@rjsf/*"
|
||||
# remark-gfm v4+ requires react-markdown v9+, which needs React 18
|
||||
- dependency-name: "remark-gfm"
|
||||
- dependency-name: "react-markdown"
|
||||
# TODO: remove below entries until React >= 19.0.0
|
||||
- dependency-name: "react-icons"
|
||||
# JSDOM v30 doesn't play well with Jest v30
|
||||
# Source: https://jestjs.io/blog#known-issues
|
||||
# GH thread: https://github.com/jsdom/jsdom/issues/3492
|
||||
- dependency-name: "jest-environment-jsdom"
|
||||
# `@swc/plugin-transform-imports` doesn't work with current Webpack-SWC hybrid setup
|
||||
# See https://github.com/apache/superset/pull/37384#issuecomment-3793991389
|
||||
# TODO: remove the plugin once Lodash usage has been migrated to a more readily tree-shakeable alternative
|
||||
- dependency-name: "@swc/plugin-transform-imports"
|
||||
# `just-handlerbars-helpers` library in plugin-chart-handlebars requires `currencyformatter`` to be < 2
|
||||
- dependency-name: "currencyformatter.js"
|
||||
update-types: ["version-update:semver-major"]
|
||||
# TODO: remove below clause once https://github.com/pmmmwh/react-refresh-webpack-plugin/pull/940 lands onto a future release
|
||||
# and confirm the issue https://github.com/apache/superset/issues/39600 is fixed
|
||||
- dependency-name: "react-checkbox-tree"
|
||||
update-types: ["version-update:semver-major"]
|
||||
groups:
|
||||
storybook:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "@storybook*"
|
||||
- "storybook"
|
||||
update-types:
|
||||
- "patch"
|
||||
directory: "/superset-frontend/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 30
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/"
|
||||
# NOTE: `uv` support is in beta, more details here:
|
||||
# https://github.com/dependabot/dependabot-core/pull/10040#issuecomment-2696978430
|
||||
- package-ecosystem: "uv"
|
||||
directory: "requirements/"
|
||||
open-pull-requests-limit: 10
|
||||
# Bump the lower bound to the new version, not just widen the upper
|
||||
# bound. Without this, a `sqlglot>=28.10.0, <29` constraint upgraded
|
||||
# to `<30` would keep the stale lower bound forever, dragging
|
||||
# transitively-resolved versions with it. See #40186 (review thread).
|
||||
versioning-strategy: increase
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
labels:
|
||||
- pip
|
||||
- uv
|
||||
- dependabot
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: ".github/actions"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 10
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/docs/"
|
||||
ignore:
|
||||
# TODO: remove below entries until React >= 18.0.0 in superset-frontend
|
||||
- dependency-name: "storybook"
|
||||
update-types: ["version-update:semver-major", "version-update:semver-minor"]
|
||||
- dependency-name: "@storybook*"
|
||||
update-types: ["version-update:semver-major", "version-update:semver-minor"]
|
||||
- dependency-name: "eslint-plugin-storybook"
|
||||
- dependency-name: "react-error-boundary"
|
||||
groups:
|
||||
storybook:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "@storybook*"
|
||||
- "storybook"
|
||||
update-types:
|
||||
- "patch"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 10
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-websocket/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-websocket/utils/client-ws-app/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 10
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
# Now for all of our plugins and packages!
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-calendar/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-histogram/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-partition/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-world-map/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-pivot-table/"
|
||||
ignore:
|
||||
# TODO: remove below entries until React >= 19.0.0
|
||||
- dependency-name: "react-icons"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-chord/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-horizon/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-rose/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-preset-chart-deckgl/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-table/"
|
||||
ignore:
|
||||
# TODO: remove below entries until React >= 19.0.0
|
||||
- dependency-name: "react-icons"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-country-map/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-map-box/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-sankey/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-preset-chart-nvd3/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-word-cloud/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-event-flow/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-paired-t-test/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-sankey-loop/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-echarts/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-ag-grid-table/"
|
||||
directory: "/superset-frontend/plugins/preset-chart-xy/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-cartodiagram/"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-heatmap/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-parallel-coordinates/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/legacy-plugin-chart-sunburst/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/plugins/plugin-chart-handlebars/"
|
||||
ignore:
|
||||
# `just-handlerbars-helpers` library in plugin-chart-handlebars requires `currencyformatter`` to be < 2
|
||||
- dependency-name: "currencyformatter.js"
|
||||
update-types: ["version-update:semver-major"]
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/packages/generator-superset/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/packages/superset-ui-chart-controls/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/packages/superset-ui-core/"
|
||||
@@ -405,25 +338,30 @@ updates:
|
||||
# not until React >= 18.0.0
|
||||
- dependency-name: "react-markdown"
|
||||
- dependency-name: "remark-gfm"
|
||||
- dependency-name: "react-error-boundary"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/packages/superset-ui-demo/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/superset-frontend/packages/superset-ui-switchboard/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
labels:
|
||||
- npm
|
||||
- dependabot
|
||||
open-pull-requests-limit: 5
|
||||
versioning-strategy: increase
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
15
.github/labeler.yml
vendored
15
.github/labeler.yml
vendored
@@ -17,11 +17,6 @@
|
||||
- any-glob-to-any-file:
|
||||
- 'superset/migrations/**'
|
||||
|
||||
"risk:ci-script":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'scripts/**'
|
||||
|
||||
############################################
|
||||
# Dependencies
|
||||
############################################
|
||||
@@ -77,11 +72,6 @@
|
||||
- any-glob-to-any-file:
|
||||
- 'superset/translations/zh/**'
|
||||
|
||||
"i18n:czech":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'superset/translations/cs/**'
|
||||
|
||||
"i18n:traditional-chinese":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
@@ -127,11 +117,6 @@
|
||||
- any-glob-to-any-file:
|
||||
- 'superset/translations/sk/**'
|
||||
|
||||
"i18n:latvian":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'superset/translations/lv/**'
|
||||
|
||||
"i18n:ukrainian":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
|
||||
240
.github/workflows/bashlib.sh
vendored
240
.github/workflows/bashlib.sh
vendored
@@ -20,6 +20,10 @@ set -e
|
||||
GITHUB_WORKSPACE=${GITHUB_WORKSPACE:-.}
|
||||
ASSETS_MANIFEST="$GITHUB_WORKSPACE/superset/static/assets/manifest.json"
|
||||
|
||||
# Rounded job start time, used to create a unique Cypress build id for
|
||||
# parallelization so we can manually rerun a job after 20 minutes
|
||||
NONCE=$(echo "$(date "+%Y%m%d%H%M") - ($(date +%M)%20)" | bc)
|
||||
|
||||
# Echo only when not in parallel mode
|
||||
say() {
|
||||
if [[ $(echo "$INPUT_PARALLEL" | tr '[:lower:]' '[:upper:]') != 'TRUE' ]]; then
|
||||
@@ -55,15 +59,6 @@ build-assets() {
|
||||
say "::endgroup::"
|
||||
}
|
||||
|
||||
build-embedded-sdk() {
|
||||
cd "$GITHUB_WORKSPACE/superset-embedded-sdk"
|
||||
|
||||
say "::group::Build embedded SDK bundle for E2E tests"
|
||||
npm ci
|
||||
npm run build
|
||||
say "::endgroup::"
|
||||
}
|
||||
|
||||
build-instrumented-assets() {
|
||||
cd "$GITHUB_WORKSPACE/superset-frontend"
|
||||
|
||||
@@ -122,33 +117,6 @@ testdata() {
|
||||
say "::endgroup::"
|
||||
}
|
||||
|
||||
playwright_testdata() {
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
say "::group::Load all examples for Playwright tests"
|
||||
# must specify PYTHONPATH to make `tests.superset_test_config` importable
|
||||
export PYTHONPATH="$GITHUB_WORKSPACE"
|
||||
pip install -e .
|
||||
superset db upgrade
|
||||
superset load_test_users
|
||||
superset load_examples
|
||||
superset init
|
||||
# Enable DML on the examples database so Playwright tests can create/drop
|
||||
# temporary tables via SQL Lab without depending on external data sources.
|
||||
superset shell <<'PYEOF'
|
||||
import sys
|
||||
from superset.extensions import db
|
||||
from superset.models.core import Database
|
||||
examples_db = db.session.query(Database).filter_by(database_name='examples').first()
|
||||
if not examples_db:
|
||||
sys.exit('ERROR: examples database not found. load_examples may have failed.')
|
||||
|
||||
examples_db.allow_dml = True
|
||||
db.session.commit()
|
||||
print('Enabled allow_dml on examples database')
|
||||
PYEOF
|
||||
say "::endgroup::"
|
||||
}
|
||||
|
||||
celery-worker() {
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
say "::group::Start Celery worker"
|
||||
@@ -180,13 +148,10 @@ cypress-run-all() {
|
||||
local APP_ROOT=$2
|
||||
cd "$GITHUB_WORKSPACE/superset-frontend/cypress-base"
|
||||
|
||||
# Start the Superset backend via gunicorn (not `flask run`). The Flask
|
||||
# development server is single-threaded and has no crash-recovery, so
|
||||
# heavy tests (dashboard import/export, SQL Lab) can knock it offline
|
||||
# for the rest of the run — surfacing as `ECONNREFUSED` / `socket hang up`
|
||||
# / `Missing CSRF token` cascades. Gunicorn gives us multiple workers,
|
||||
# a request timeout, and worker-recycling under load.
|
||||
local serverlog="${HOME}/superset-cypress.log"
|
||||
# Start Flask and run it in background
|
||||
# --no-debugger means disable the interactive debugger on the 500 page
|
||||
# so errors can print to stderr.
|
||||
local flasklog="${HOME}/flask.log"
|
||||
local port=8081
|
||||
CYPRESS_BASE_URL="http://localhost:${port}"
|
||||
if [ -n "$APP_ROOT" ]; then
|
||||
@@ -195,58 +160,8 @@ cypress-run-all() {
|
||||
fi
|
||||
export CYPRESS_BASE_URL
|
||||
|
||||
# Mirrors the args in docker/entrypoints/run-server.sh (1 worker × 20
|
||||
# gthread threads) to keep parity with production. Multi-worker
|
||||
# configurations expose timing-sensitive races in the SQL Lab → Explore
|
||||
# navigation flow under E2E. We diverge from the entrypoint on:
|
||||
# --timeout 120: heavy dashboard import/export specs exceed the 60s
|
||||
# default
|
||||
# --max-requests / --max-requests-jitter: recycle the worker under
|
||||
# test load to avoid leaks accumulating across the run
|
||||
# superset.app:create_app(): explicit factory so we don't depend on
|
||||
# FLASK_APP being exported
|
||||
nohup gunicorn \
|
||||
--bind "127.0.0.1:$port" \
|
||||
--workers 1 \
|
||||
--worker-class gthread \
|
||||
--threads 20 \
|
||||
--timeout 120 \
|
||||
--max-requests 500 \
|
||||
--max-requests-jitter 50 \
|
||||
--access-logfile - \
|
||||
--error-logfile - \
|
||||
"superset.app:create_app()" \
|
||||
>"$serverlog" 2>&1 </dev/null &
|
||||
local serverPid=$!
|
||||
|
||||
# Ensure the backend is cleaned up and its log is emitted even when the
|
||||
# test runner fails under `set -e`.
|
||||
trap '
|
||||
echo "::group::gunicorn log for Cypress run"
|
||||
cat "'"$serverlog"'" || true
|
||||
echo "::endgroup::"
|
||||
kill '"$serverPid"' 2>/dev/null || true
|
||||
' EXIT
|
||||
|
||||
# Wait for the backend to be ready before launching Cypress; otherwise
|
||||
# the first spec can race the server bind and see connection errors.
|
||||
local timeout=60
|
||||
say "Waiting for gunicorn server to start on port $port..."
|
||||
while [ $timeout -gt 0 ]; do
|
||||
if curl -f "http://localhost:${port}${APP_ROOT}/health" >/dev/null 2>&1; then
|
||||
say "gunicorn server is ready"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
timeout=$((timeout - 1))
|
||||
done
|
||||
if [ $timeout -eq 0 ]; then
|
||||
echo "::error::gunicorn server failed to start within 60 seconds"
|
||||
echo "::group::Server startup log"
|
||||
cat "$serverlog"
|
||||
echo "::endgroup::"
|
||||
return 1
|
||||
fi
|
||||
nohup flask run --no-debugger -p $port >"$flasklog" 2>&1 </dev/null &
|
||||
local flaskProcessId=$!
|
||||
|
||||
USE_DASHBOARD_FLAG=''
|
||||
if [ "$USE_DASHBOARD" = "true" ]; then
|
||||
@@ -258,113 +173,13 @@ cypress-run-all() {
|
||||
# memoryMonitorPid=$!
|
||||
python ../../scripts/cypress_run.py --parallelism $PARALLELISM --parallelism-id $PARALLEL_ID --group $PARALLEL_ID --retries 5 $USE_DASHBOARD_FLAG
|
||||
# kill $memoryMonitorPid
|
||||
}
|
||||
|
||||
playwright-install() {
|
||||
cd "$GITHUB_WORKSPACE/superset-frontend"
|
||||
|
||||
say "::group::Install Playwright browsers"
|
||||
npx playwright install --with-deps chromium
|
||||
# Create output directories for test results and debugging
|
||||
mkdir -p playwright-results
|
||||
mkdir -p test-results
|
||||
say "::endgroup::"
|
||||
}
|
||||
|
||||
playwright-run() {
|
||||
local APP_ROOT=$1
|
||||
local TEST_PATH=$2
|
||||
|
||||
# Start the Superset backend via gunicorn from the project root.
|
||||
# See cypress-run-all() above for the rationale — the Flask dev server
|
||||
# cannot survive the dashboard import/export tests under load.
|
||||
cd "$GITHUB_WORKSPACE"
|
||||
local serverlog="${HOME}/superset-playwright.log"
|
||||
local port=8081
|
||||
# Use 127.0.0.1 explicitly: `flask run` binds IPv4 only, and Node's DNS
|
||||
# resolution for `localhost` can return `::1` first (IPv6), which then
|
||||
# refuses against the IPv4 listener and surfaces as
|
||||
# `connect ECONNREFUSED ::1:<port>` in API helpers driven from Node
|
||||
# (e.g., the embedded test app's exposed token fetcher).
|
||||
PLAYWRIGHT_BASE_URL="http://127.0.0.1:${port}"
|
||||
if [ -n "$APP_ROOT" ]; then
|
||||
export SUPERSET_APP_ROOT=$APP_ROOT
|
||||
PLAYWRIGHT_BASE_URL=${PLAYWRIGHT_BASE_URL}${APP_ROOT}/
|
||||
fi
|
||||
export PLAYWRIGHT_BASE_URL
|
||||
|
||||
# See cypress-run-all() above for the args rationale (1 worker × 20
|
||||
# gthread threads matching docker/entrypoints/run-server.sh, plus a
|
||||
# 120s timeout and request-recycling for heavy E2E load).
|
||||
nohup gunicorn \
|
||||
--bind "127.0.0.1:$port" \
|
||||
--workers 1 \
|
||||
--worker-class gthread \
|
||||
--threads 20 \
|
||||
--timeout 120 \
|
||||
--max-requests 500 \
|
||||
--max-requests-jitter 50 \
|
||||
--access-logfile - \
|
||||
--error-logfile - \
|
||||
"superset.app:create_app()" \
|
||||
>"$serverlog" 2>&1 </dev/null &
|
||||
local serverPid=$!
|
||||
|
||||
# Ensure cleanup on exit (and emit the server log on failure)
|
||||
trap '
|
||||
echo "::group::gunicorn log for Playwright run"
|
||||
cat "'"$serverlog"'" || true
|
||||
echo "::endgroup::"
|
||||
kill '"$serverPid"' 2>/dev/null || true
|
||||
' EXIT
|
||||
|
||||
# Wait for server to be ready with health check
|
||||
local timeout=60
|
||||
say "Waiting for gunicorn server to start on port $port..."
|
||||
while [ $timeout -gt 0 ]; do
|
||||
if curl -f ${PLAYWRIGHT_BASE_URL}/health >/dev/null 2>&1; then
|
||||
say "gunicorn server is ready"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
timeout=$((timeout - 1))
|
||||
done
|
||||
|
||||
if [ $timeout -eq 0 ]; then
|
||||
echo "::error::gunicorn server failed to start within 60 seconds"
|
||||
echo "::group::Server startup log"
|
||||
cat "$serverlog"
|
||||
echo "::endgroup::"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Change to frontend directory for Playwright execution
|
||||
cd "$GITHUB_WORKSPACE/superset-frontend"
|
||||
|
||||
say "::group::Run Playwright tests"
|
||||
echo "Running Playwright with baseURL: ${PLAYWRIGHT_BASE_URL}"
|
||||
if [ -n "$TEST_PATH" ]; then
|
||||
# Check if there are any test files in the specified path
|
||||
if ! find "playwright/tests/${TEST_PATH}" -name "*.spec.ts" -type f 2>/dev/null | grep -q .; then
|
||||
echo "No test files found in ${TEST_PATH} - skipping test run"
|
||||
say "::endgroup::"
|
||||
return 0
|
||||
fi
|
||||
echo "Running tests: ${TEST_PATH}"
|
||||
# Set INCLUDE_EXPERIMENTAL=true to allow experimental tests to run
|
||||
export INCLUDE_EXPERIMENTAL=true
|
||||
npx playwright test "${TEST_PATH}" --output=playwright-results
|
||||
local status=$?
|
||||
# Unset to prevent leaking into subsequent commands
|
||||
unset INCLUDE_EXPERIMENTAL
|
||||
else
|
||||
echo "Running all required tests (experimental/ excluded via playwright.config.ts)"
|
||||
npx playwright test --output=playwright-results
|
||||
local status=$?
|
||||
fi
|
||||
say "::endgroup::"
|
||||
|
||||
return $status
|
||||
# After job is done, print out Flask log for debugging
|
||||
echo "::group::Flask log for default run"
|
||||
cat "$flasklog"
|
||||
echo "::endgroup::"
|
||||
# make sure the program exits
|
||||
kill $flaskProcessId
|
||||
}
|
||||
|
||||
eyes-storybook-dependencies() {
|
||||
@@ -387,3 +202,26 @@ monitor_memory() {
|
||||
sleep 2
|
||||
done
|
||||
}
|
||||
|
||||
cypress-run-applitools() {
|
||||
cd "$GITHUB_WORKSPACE/superset-frontend/cypress-base"
|
||||
|
||||
local flasklog="${HOME}/flask.log"
|
||||
local port=8081
|
||||
local cypress="./node_modules/.bin/cypress run"
|
||||
local browser=${CYPRESS_BROWSER:-chrome}
|
||||
|
||||
export CYPRESS_BASE_URL="http://localhost:${port}"
|
||||
|
||||
nohup flask run --no-debugger -p $port >"$flasklog" 2>&1 </dev/null &
|
||||
local flaskProcessId=$!
|
||||
|
||||
$cypress --spec "cypress/applitools/**/*" --browser "$browser" --headless
|
||||
|
||||
say "::group::Flask log for default run"
|
||||
cat "$flasklog"
|
||||
say "::endgroup::"
|
||||
|
||||
# make sure the program exits
|
||||
kill $flaskProcessId
|
||||
}
|
||||
|
||||
20
.github/workflows/bump-python-package.yml
vendored
20
.github/workflows/bump-python-package.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: true
|
||||
ref: master
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
uses: ./.github/actions/setup-supersetbot/
|
||||
|
||||
- name: Set up Python ${{ inputs.python-version }}
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
@@ -51,31 +51,27 @@ jobs:
|
||||
- name: supersetbot bump-python -p "${{ github.event.inputs.package }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
INPUT_PACKAGE: ${{ github.event.inputs.package }}
|
||||
INPUT_GROUP: ${{ github.event.inputs.group }}
|
||||
INPUT_EXTRA_FLAGS: ${{ github.event.inputs.extra-flags }}
|
||||
INPUT_LIMIT: ${{ github.event.inputs.limit }}
|
||||
run: |
|
||||
git config --global user.email "action@github.com"
|
||||
git config --global user.name "GitHub Action"
|
||||
|
||||
PACKAGE_OPT=""
|
||||
if [ -n "${INPUT_PACKAGE}" ]; then
|
||||
PACKAGE_OPT="-p ${INPUT_PACKAGE}"
|
||||
if [ -n "${{ github.event.inputs.package }}" ]; then
|
||||
PACKAGE_OPT="-p ${{ github.event.inputs.package }}"
|
||||
fi
|
||||
|
||||
GROUP_OPT=""
|
||||
if [ -n "${INPUT_GROUP}" ]; then
|
||||
GROUP_OPT="-g ${INPUT_GROUP}"
|
||||
if [ -n "${{ github.event.inputs.group }}" ]; then
|
||||
GROUP_OPT="-g ${{ github.event.inputs.group }}"
|
||||
fi
|
||||
|
||||
EXTRA_FLAGS="${INPUT_EXTRA_FLAGS}"
|
||||
EXTRA_FLAGS="${{ github.event.inputs.extra-flags }}"
|
||||
|
||||
supersetbot bump-python \
|
||||
--verbose \
|
||||
--use-current-repo \
|
||||
--include-subpackages \
|
||||
--limit ${INPUT_LIMIT} \
|
||||
--limit ${{ github.event.inputs.limit }} \
|
||||
$PACKAGE_OPT \
|
||||
$GROUP_OPT \
|
||||
$EXTRA_FLAGS
|
||||
|
||||
43
.github/workflows/cancel_duplicates.yml
vendored
Normal file
43
.github/workflows/cancel_duplicates.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Cancel Duplicates
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- "Miscellaneous"
|
||||
types:
|
||||
- requested
|
||||
|
||||
jobs:
|
||||
cancel-duplicate-runs:
|
||||
name: Cancel duplicate workflow runs
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
actions: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Check number of queued tasks
|
||||
id: check_queued
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
GITHUB_REPO: ${{ github.repository }}
|
||||
run: |
|
||||
get_count() {
|
||||
echo $(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/$GITHUB_REPO/actions/runs?status=$1" | \
|
||||
jq ".total_count")
|
||||
}
|
||||
count=$(( `get_count queued` + `get_count in_progress` ))
|
||||
echo "Found $count unfinished jobs."
|
||||
echo "count=$count" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
if: steps.check_queued.outputs.count >= 20
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Cancel duplicate workflow runs
|
||||
if: steps.check_queued.outputs.count >= 20
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
run: |
|
||||
pip install click requests typing_extensions python-dateutil
|
||||
python ./scripts/cancel_github_workflows.py
|
||||
19
.github/workflows/check-python-deps.yml
vendored
19
.github/workflows/check-python-deps.yml
vendored
@@ -8,10 +8,6 @@ on:
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
@@ -22,7 +18,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
@@ -38,19 +34,6 @@ jobs:
|
||||
if: steps.check.outputs.python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
|
||||
# Authenticate the Docker daemon so the python:slim pull in
|
||||
# uv-pip-compile.sh uses our (much higher) authenticated rate limit
|
||||
# instead of the shared-runner anonymous one. Best-effort: on fork PRs the
|
||||
# secrets are unavailable, so this no-ops and the pull falls back to
|
||||
# anonymous (covered by the retry loop in the script).
|
||||
- name: Login to Docker Hub
|
||||
if: steps.check.outputs.python
|
||||
continue-on-error: true
|
||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USER }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Run uv
|
||||
if: steps.check.outputs.python
|
||||
run: ./scripts/uv-pip-compile.sh
|
||||
|
||||
@@ -25,11 +25,9 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v5
|
||||
- name: Check and notify
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
script: |
|
||||
@@ -71,7 +69,7 @@ jobs:
|
||||
`❗ @${pull.user.login} Your base branch \`${currentBranch}\` has ` +
|
||||
'also updated `superset/migrations`.\n' +
|
||||
'\n' +
|
||||
'**Please consider rebasing your branch and [resolving potential db migration conflicts](https://superset.apache.org/docs/contributing/development#merging-db-migrations).**',
|
||||
'**Please consider rebasing your branch and [resolving potential db migration conflicts](https://github.com/apache/superset/blob/master/CONTRIBUTING.md#merging-db-migrations).**',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
20
.github/workflows/claude.yml
vendored
20
.github/workflows/claude.yml
vendored
@@ -6,9 +6,6 @@ on:
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check-permissions:
|
||||
if: |
|
||||
@@ -20,12 +17,13 @@ jobs:
|
||||
steps:
|
||||
- name: Check if user is allowed
|
||||
id: check
|
||||
env:
|
||||
COMMENTER: ${{ github.event.comment.user.login }}
|
||||
run: |
|
||||
# List of allowed users
|
||||
ALLOWED_USERS="mistercrunch,rusackas"
|
||||
|
||||
# Get the commenter's username
|
||||
COMMENTER="${{ github.event.comment.user.login }}"
|
||||
|
||||
echo "Checking permissions for user: $COMMENTER"
|
||||
|
||||
# Check if user is in allowed list
|
||||
@@ -46,13 +44,10 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Comment access denied
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
env:
|
||||
COMMENTER_LOGIN: ${{ github.event.comment.user.login || github.event.review.user.login || github.event.issue.user.login }}
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const commenter = process.env.COMMENTER_LOGIN;
|
||||
const message = `👋 Hi @${commenter}!
|
||||
const message = `👋 Hi @${{ github.event.comment.user.login || github.event.review.user.login || github.event.issue.user.login }}!
|
||||
|
||||
Thanks for trying to use Claude Code, but currently only certain team members have access to this feature.
|
||||
|
||||
@@ -76,13 +71,12 @@ jobs:
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude PR Action
|
||||
uses: anthropics/claude-code-action@5fb899572b81d2bb648d4d187173a2f423a9677c # beta
|
||||
uses: anthropics/claude-code-action@beta
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
timeout_minutes: "60"
|
||||
|
||||
39
.github/workflows/codeql-analysis.yml
vendored
39
.github/workflows/codeql-analysis.yml
vendored
@@ -15,35 +15,9 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
outputs:
|
||||
python: ${{ steps.check.outputs.python }}
|
||||
frontend: ${{ steps.check.outputs.frontend }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
analyze:
|
||||
name: Analyze
|
||||
needs: changes
|
||||
# Skip on PRs that touch neither code group (e.g. docs-only) so the
|
||||
# analysis runners don't spin up. push/schedule runs always proceed:
|
||||
# the change-detector returns "all changed" for non-PR events.
|
||||
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
@@ -57,13 +31,17 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
persist-credentials: false
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -74,6 +52,7 @@ jobs:
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4
|
||||
if: steps.check.outputs.python || steps.check.outputs.frontend
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
16
.github/workflows/dependency-review.yml
vendored
16
.github/workflows/dependency-review.yml
vendored
@@ -27,11 +27,9 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout Repository"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v5
|
||||
- name: "Dependency Review"
|
||||
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
|
||||
uses: actions/dependency-review-action@v4
|
||||
continue-on-error: true
|
||||
with:
|
||||
fail-on-severity: critical
|
||||
@@ -41,9 +39,13 @@ jobs:
|
||||
# pkg:npm/store2@2.14.2
|
||||
# adding an exception for an ambigious license on store2, which has been resolved in
|
||||
# the latest version. It's MIT: https://github.com/nbubna/store/blob/master/LICENSE-MIT
|
||||
# pkg:npm/applitools/*
|
||||
# adding exception for all applitools modules (eyes-cypress and its dependencies),
|
||||
# which has an explicit OSS license approved by ASF
|
||||
# license: https://applitools.com/legal/open-source-terms-of-use/
|
||||
# pkg:npm/node-forge@1.3.1
|
||||
# selecting BSD-3-Clause licensing terms for node-forge to ensure compatibility with Apache
|
||||
allow-dependencies-licenses: pkg:npm/store2@2.14.2, pkg:npm/node-forge@1.3.1, pkg:npm/rgbcolor, pkg:npm/jszip@3.10.1
|
||||
allow-dependencies-licenses: pkg:npm/store2@2.14.2, pkg:npm/applitools/core, pkg:npm/applitools/core-base, pkg:npm/applitools/css-tree, pkg:npm/applitools/ec-client, pkg:npm/applitools/eg-socks5-proxy-server, pkg:npm/applitools/eyes, pkg:npm/applitools/eyes-cypress, pkg:npm/applitools/nml-client, pkg:npm/applitools/tunnel-client, pkg:npm/applitools/utils, pkg:npm/node-forge@1.3.1, pkg:npm/rgbcolor, pkg:npm/jszip@3.10.1
|
||||
|
||||
python-dependency-liccheck:
|
||||
# NOTE: Configuration for liccheck lives in our pyproject.yml.
|
||||
@@ -51,9 +53,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: "Checkout Repository"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
|
||||
79
.github/workflows/docker.yml
vendored
79
.github/workflows/docker.yml
vendored
@@ -9,40 +9,14 @@ on:
|
||||
branches:
|
||||
- "master"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
outputs:
|
||||
python: ${{ steps.check.outputs.python }}
|
||||
frontend: ${{ steps.check.outputs.frontend }}
|
||||
docker: ${{ steps.check.outputs.docker }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
setup_matrix:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
matrix_config: ${{ steps.set_matrix.outputs.matrix_config }}
|
||||
steps:
|
||||
@@ -54,13 +28,8 @@ jobs:
|
||||
|
||||
docker-build:
|
||||
name: docker-build
|
||||
needs: [setup_matrix, changes]
|
||||
if: >-
|
||||
needs.changes.outputs.python == 'true' ||
|
||||
needs.changes.outputs.frontend == 'true' ||
|
||||
needs.changes.outputs.docker == 'true'
|
||||
needs: setup_matrix
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
matrix:
|
||||
build_preset: ${{fromJson(needs.setup_matrix.outputs.matrix_config)}}
|
||||
@@ -73,11 +42,18 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Setup Docker Environment
|
||||
if: steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker
|
||||
uses: ./.github/actions/setup-docker
|
||||
with:
|
||||
dockerhub-user: ${{ secrets.DOCKERHUB_USER }}
|
||||
@@ -85,27 +61,28 @@ jobs:
|
||||
build: "true"
|
||||
|
||||
- name: Setup supersetbot
|
||||
if: steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker
|
||||
uses: ./.github/actions/setup-supersetbot/
|
||||
|
||||
- name: Build Docker Image
|
||||
if: steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BUILD_PRESET: ${{ matrix.build_preset }}
|
||||
run: |
|
||||
# Single platform builds in pull_request context to speed things up
|
||||
if [ "$GITHUB_EVENT_NAME" = "push" ]; then
|
||||
if [ "${{ github.event_name }}" = "push" ]; then
|
||||
PLATFORM_ARG="--platform linux/arm64 --platform linux/amd64"
|
||||
# can only --load images in single-platform builds
|
||||
PUSH_OR_LOAD="--push"
|
||||
elif [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
|
||||
elif [ "${{ github.event_name }}" = "pull_request" ]; then
|
||||
PLATFORM_ARG="--platform linux/amd64"
|
||||
PUSH_OR_LOAD="--load"
|
||||
fi
|
||||
|
||||
supersetbot docker \
|
||||
$PUSH_OR_LOAD \
|
||||
--preset "$BUILD_PRESET" \
|
||||
--preset ${{ matrix.build_preset }} \
|
||||
--context "$EVENT" \
|
||||
--context-ref "$RELEASE" $FORCE_LATEST \
|
||||
--extra-flags "--build-arg INCLUDE_CHROMIUM=false --tag $IMAGE_TAG" \
|
||||
@@ -113,14 +90,11 @@ jobs:
|
||||
|
||||
# in the context of push (using multi-platform build), we need to pull the image locally
|
||||
- name: Docker pull
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
for i in 1 2 3; do
|
||||
docker pull $IMAGE_TAG && break
|
||||
[ $i -lt 3 ] && sleep 30
|
||||
done
|
||||
if: github.event_name == 'push' && (steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker)
|
||||
run: docker pull $IMAGE_TAG
|
||||
|
||||
- name: Print docker stats
|
||||
if: steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker
|
||||
run: |
|
||||
echo "SHA: ${{ github.sha }}"
|
||||
echo "IMAGE: $IMAGE_TAG"
|
||||
@@ -128,12 +102,10 @@ jobs:
|
||||
docker history $IMAGE_TAG
|
||||
|
||||
- name: docker-compose sanity check
|
||||
if: matrix.build_preset == 'dev'
|
||||
if: (steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker) && matrix.build_preset == 'dev'
|
||||
shell: bash
|
||||
env:
|
||||
BUILD_PRESET: ${{ matrix.build_preset }}
|
||||
run: |
|
||||
export SUPERSET_BUILD_TARGET=$BUILD_PRESET
|
||||
export SUPERSET_BUILD_TARGET=${{ matrix.build_preset }}
|
||||
# This should reuse the CACHED image built in the previous steps
|
||||
docker compose build superset-init --build-arg DEV_MODE=false --build-arg INCLUDE_CHROMIUM=false
|
||||
docker compose up superset-init --exit-code-from superset-init
|
||||
@@ -141,16 +113,20 @@ jobs:
|
||||
docker-compose-image-tag:
|
||||
# Run this job only on pushes to master (not for PRs)
|
||||
# goal is to check that building the latest image works, not required for all PR pushes
|
||||
needs: changes
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && needs.changes.outputs.docker == 'true'
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Setup Docker Environment
|
||||
if: steps.check.outputs.docker
|
||||
uses: ./.github/actions/setup-docker
|
||||
with:
|
||||
dockerhub-user: ${{ secrets.DOCKERHUB_USER }}
|
||||
@@ -158,6 +134,7 @@ jobs:
|
||||
build: "false"
|
||||
install-docker-compose: "true"
|
||||
- name: docker-compose sanity check
|
||||
if: steps.check.outputs.docker
|
||||
shell: bash
|
||||
run: |
|
||||
docker compose -f docker-compose-image-tag.yml up superset-init --exit-code-from superset-init
|
||||
|
||||
13
.github/workflows/embedded-sdk-release.yml
vendored
13
.github/workflows/embedded-sdk-release.yml
vendored
@@ -6,9 +6,6 @@ on:
|
||||
- "master"
|
||||
- "[0-9].[0-9]*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -19,12 +16,10 @@ jobs:
|
||||
id: check
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${NPM_TOKEN}" ]; then
|
||||
if [ -n "${{ (secrets.NPM_TOKEN != '') || '' }}" ]; then
|
||||
echo "has-secrets=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
env:
|
||||
NPM_TOKEN: ${{ (secrets.NPM_TOKEN != '') || '' }}
|
||||
build:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
@@ -33,10 +28,8 @@ jobs:
|
||||
run:
|
||||
working-directory: superset-embedded-sdk
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './superset-embedded-sdk/.nvmrc'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
9
.github/workflows/embedded-sdk-test.yml
vendored
9
.github/workflows/embedded-sdk-test.yml
vendored
@@ -6,9 +6,6 @@ on:
|
||||
- "superset-embedded-sdk/**"
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
@@ -21,10 +18,8 @@ jobs:
|
||||
run:
|
||||
working-directory: superset-embedded-sdk
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './superset-embedded-sdk/.nvmrc'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
81
.github/workflows/ephemeral-env-pr-close.yml
vendored
Normal file
81
.github/workflows/ephemeral-env-pr-close.yml
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
name: Cleanup ephemeral envs (PR close) [DEPRECATED]
|
||||
|
||||
# ⚠️ DEPRECATION NOTICE ⚠️
|
||||
# This workflow is deprecated and will be removed in a future version.
|
||||
# The new Superset Showtime workflow handles cleanup automatically.
|
||||
# See .github/workflows/showtime.yml and showtime-cleanup.yml for replacements.
|
||||
# Migration guide: https://github.com/mistercrunch/superset-showtime
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [closed]
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
has-secrets: ${{ steps.check.outputs.has-secrets }}
|
||||
steps:
|
||||
- name: "Check for secrets"
|
||||
id: check
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${{ (secrets.AWS_ACCESS_KEY_ID != '' && secrets.AWS_SECRET_ACCESS_KEY != '') || '' }}" ]; then
|
||||
echo "has-secrets=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
ephemeral-env-cleanup:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
name: Cleanup ephemeral envs
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-west-2
|
||||
|
||||
- name: Describe ECS service
|
||||
id: describe-services
|
||||
run: |
|
||||
echo "active=$(aws ecs describe-services --cluster superset-ci --services pr-${{ github.event.number }}-service | jq '.services[] | select(.status == "ACTIVE") | any')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Delete ECS service
|
||||
if: steps.describe-services.outputs.active == 'true'
|
||||
id: delete-service
|
||||
run: |
|
||||
aws ecs delete-service \
|
||||
--cluster superset-ci \
|
||||
--service pr-${{ github.event.number }}-service \
|
||||
--force
|
||||
|
||||
- name: Login to Amazon ECR
|
||||
if: steps.describe-services.outputs.active == 'true'
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
|
||||
- name: Delete ECR image tag
|
||||
if: steps.describe-services.outputs.active == 'true'
|
||||
id: delete-image-tag
|
||||
run: |
|
||||
aws ecr batch-delete-image \
|
||||
--registry-id $(echo "${{ steps.login-ecr.outputs.registry }}" | grep -Eo "^[0-9]+") \
|
||||
--repository-name superset-ci \
|
||||
--image-ids imageTag=pr-${{ github.event.number }}
|
||||
|
||||
- name: Comment (success)
|
||||
if: steps.describe-services.outputs.active == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{github.token}}
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
issue_number: ${{ github.event.number }},
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: '⚠️ **DEPRECATED WORKFLOW** - Ephemeral environment shutdown and build artifacts deleted. Please migrate to the new Superset Showtime system for future PRs.'
|
||||
})
|
||||
344
.github/workflows/ephemeral-env.yml
vendored
Normal file
344
.github/workflows/ephemeral-env.yml
vendored
Normal file
@@ -0,0 +1,344 @@
|
||||
name: Ephemeral env workflow [DEPRECATED]
|
||||
|
||||
# ⚠️ DEPRECATION NOTICE ⚠️
|
||||
# This workflow is deprecated and will be removed in a future version.
|
||||
# Please use the new Superset Showtime workflow instead:
|
||||
# - Use label "🎪 trigger-start" instead of "testenv-up"
|
||||
# - Showtime provides better reliability and easier management
|
||||
# - See .github/workflows/showtime.yml for the replacement
|
||||
# - Migration guide: https://github.com/mistercrunch/superset-showtime
|
||||
|
||||
# Example manual trigger:
|
||||
# gh workflow run ephemeral-env.yml --ref fix_ephemerals --field label_name="testenv-up" --field issue_number=666
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- labeled
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
label_name:
|
||||
description: 'Label name to simulate label-based /testenv trigger'
|
||||
required: true
|
||||
default: 'testenv-up'
|
||||
issue_number:
|
||||
description: 'Issue or PR number'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
ephemeral-env-label:
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}-label
|
||||
cancel-in-progress: true
|
||||
name: Evaluate ephemeral env label trigger
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
pull-requests: write
|
||||
outputs:
|
||||
slash-command: ${{ steps.eval-label.outputs.result }}
|
||||
feature-flags: ${{ steps.eval-feature-flags.outputs.result }}
|
||||
sha: ${{ steps.get-sha.outputs.sha }}
|
||||
env:
|
||||
DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
|
||||
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
steps:
|
||||
- name: Check for the "testenv-up" label
|
||||
id: eval-label
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
||||
LABEL_NAME="${{ github.event.inputs.label_name }}"
|
||||
else
|
||||
LABEL_NAME="${{ github.event.label.name }}"
|
||||
fi
|
||||
|
||||
echo "Evaluating label: $LABEL_NAME"
|
||||
|
||||
if [[ "$LABEL_NAME" == "testenv-up" ]]; then
|
||||
echo "result=up" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "result=noop" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Get event SHA
|
||||
id: get-sha
|
||||
if: steps.eval-label.outputs.result == 'up'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
let prSha;
|
||||
|
||||
// If event is workflow_dispatch, use the issue_number from inputs
|
||||
if (context.eventName === "workflow_dispatch") {
|
||||
const prNumber = "${{ github.event.inputs.issue_number }}";
|
||||
if (!prNumber) {
|
||||
console.log("No PR number found.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch PR details using the provided issue_number
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: prNumber
|
||||
});
|
||||
|
||||
prSha = pr.head.sha;
|
||||
} else {
|
||||
// If it's not workflow_dispatch, use the PR head sha from the event
|
||||
prSha = context.payload.pull_request.head.sha;
|
||||
}
|
||||
|
||||
console.log(`PR SHA: ${prSha}`);
|
||||
core.setOutput("sha", prSha);
|
||||
|
||||
- name: Looking for feature flags in PR description
|
||||
uses: actions/github-script@v7
|
||||
id: eval-feature-flags
|
||||
if: steps.eval-label.outputs.result == 'up'
|
||||
with:
|
||||
script: |
|
||||
const description = context.payload.pull_request
|
||||
? context.payload.pull_request.body || ''
|
||||
: context.payload.inputs.pr_description || '';
|
||||
|
||||
const pattern = /FEATURE_(\w+)=(\w+)/g;
|
||||
let results = [];
|
||||
[...description.matchAll(pattern)].forEach(match => {
|
||||
const config = {
|
||||
name: `SUPERSET_FEATURE_${match[1]}`,
|
||||
value: match[2],
|
||||
};
|
||||
results.push(config);
|
||||
});
|
||||
|
||||
return results;
|
||||
|
||||
- name: Reply with confirmation comment
|
||||
uses: actions/github-script@v7
|
||||
if: steps.eval-label.outputs.result == 'up'
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const action = '${{ steps.eval-label.outputs.result }}';
|
||||
const user = context.actor;
|
||||
const runId = context.runId;
|
||||
const workflowUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`;
|
||||
|
||||
const issueNumber = context.payload.pull_request
|
||||
? context.payload.pull_request.number
|
||||
: context.payload.inputs.issue_number;
|
||||
|
||||
if (!issueNumber) {
|
||||
throw new Error("Issue number is not available.");
|
||||
}
|
||||
|
||||
const body = `⚠️ **DEPRECATED WORKFLOW** ⚠️\n\n@${user} This workflow is deprecated! Please use the new **Superset Showtime** system instead:\n\n` +
|
||||
`- Replace "testenv-up" label with "🎪 trigger-start"\n` +
|
||||
`- Better reliability and easier management\n` +
|
||||
`- See https://github.com/mistercrunch/superset-showtime for details\n\n` +
|
||||
`Processing your ephemeral environment request [here](${workflowUrl}). Action: **${action}**.` +
|
||||
` More information on [how to use or configure ephemeral environments]` +
|
||||
`(https://superset.apache.org/docs/contributing/howtos/#github-ephemeral-environments)`;
|
||||
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
body,
|
||||
});
|
||||
|
||||
ephemeral-docker-build:
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}-build
|
||||
cancel-in-progress: true
|
||||
needs: ephemeral-env-label
|
||||
if: needs.ephemeral-env-label.outputs.slash-command == 'up'
|
||||
name: ephemeral-docker-build
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ needs.ephemeral-env-label.outputs.sha }} : ${{steps.get-sha.outputs.sha}} )"
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ needs.ephemeral-env-label.outputs.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Docker Environment
|
||||
uses: ./.github/actions/setup-docker
|
||||
with:
|
||||
dockerhub-user: ${{ secrets.DOCKERHUB_USER }}
|
||||
dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
build: "true"
|
||||
install-docker-compose: "false"
|
||||
|
||||
- name: Setup supersetbot
|
||||
uses: ./.github/actions/setup-supersetbot/
|
||||
|
||||
- name: Build ephemeral env image
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
supersetbot docker \
|
||||
--push \
|
||||
--load \
|
||||
--preset ci \
|
||||
--platform linux/amd64 \
|
||||
--context-ref "$RELEASE" \
|
||||
--extra-flags "--build-arg INCLUDE_CHROMIUM=false"
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-west-2
|
||||
|
||||
- name: Login to Amazon ECR
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
|
||||
- name: Load, tag and push image to ECR
|
||||
id: push-image
|
||||
env:
|
||||
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
|
||||
ECR_REPOSITORY: superset-ci
|
||||
IMAGE_TAG: apache/superset:${{ needs.ephemeral-env-label.outputs.sha }}-ci
|
||||
PR_NUMBER: ${{ github.event.inputs.issue_number || github.event.pull_request.number }}
|
||||
run: |
|
||||
docker tag $IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:pr-$PR_NUMBER-ci
|
||||
docker push -a $ECR_REGISTRY/$ECR_REPOSITORY
|
||||
|
||||
ephemeral-env-up:
|
||||
needs: [ephemeral-env-label, ephemeral-docker-build]
|
||||
if: needs.ephemeral-env-label.outputs.slash-command == 'up'
|
||||
name: Spin up an ephemeral environment
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-west-2
|
||||
|
||||
- name: Login to Amazon ECR
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
|
||||
- name: Check target image exists in ECR
|
||||
id: check-image
|
||||
continue-on-error: true
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.inputs.issue_number || github.event.pull_request.number }}
|
||||
run: |
|
||||
aws ecr describe-images \
|
||||
--registry-id $(echo "${{ steps.login-ecr.outputs.registry }}" | grep -Eo "^[0-9]+") \
|
||||
--repository-name superset-ci \
|
||||
--image-ids imageTag=pr-$PR_NUMBER-ci
|
||||
|
||||
- name: Fail on missing container image
|
||||
if: steps.check-image.outcome == 'failure'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
script: |
|
||||
const errMsg = '@${{ github.event.comment.user.login }} Container image not yet published for this PR. Please try again when build is complete.';
|
||||
github.rest.issues.createComment({
|
||||
issue_number: ${{ github.event.inputs.issue_number || github.event.pull_request.number }},
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: errMsg
|
||||
});
|
||||
core.setFailed(errMsg);
|
||||
|
||||
- name: Fill in the new image ID in the Amazon ECS task definition
|
||||
id: task-def
|
||||
uses: aws-actions/amazon-ecs-render-task-definition@v1
|
||||
with:
|
||||
task-definition: .github/workflows/ecs-task-definition.json
|
||||
container-name: superset-ci
|
||||
image: ${{ steps.login-ecr.outputs.registry }}/superset-ci:pr-${{ github.event.inputs.issue_number || github.event.pull_request.number }}-ci
|
||||
|
||||
- name: Update env vars in the Amazon ECS task definition
|
||||
run: |
|
||||
cat <<< "$(jq '.containerDefinitions[0].environment += ${{ needs.ephemeral-env-label.outputs.feature-flags }}' < ${{ steps.task-def.outputs.task-definition }})" > ${{ steps.task-def.outputs.task-definition }}
|
||||
|
||||
- name: Describe ECS service
|
||||
id: describe-services
|
||||
run: |
|
||||
echo "active=$(aws ecs describe-services --cluster superset-ci --services pr-${{ github.event.inputs.issue_number || github.event.pull_request.number }}-service | jq '.services[] | select(.status == "ACTIVE") | any')" >> $GITHUB_OUTPUT
|
||||
- name: Create ECS service
|
||||
id: create-service
|
||||
if: steps.describe-services.outputs.active != 'true'
|
||||
env:
|
||||
ECR_SUBNETS: subnet-0e15a5034b4121710,subnet-0e8efef4a72224974
|
||||
ECR_SECURITY_GROUP: sg-092ff3a6ae0574d91
|
||||
PR_NUMBER: ${{ github.event.inputs.issue_number || github.event.pull_request.number }}
|
||||
run: |
|
||||
aws ecs create-service \
|
||||
--cluster superset-ci \
|
||||
--service-name pr-$PR_NUMBER-service \
|
||||
--task-definition superset-ci \
|
||||
--launch-type FARGATE \
|
||||
--desired-count 1 \
|
||||
--platform-version LATEST \
|
||||
--network-configuration "awsvpcConfiguration={subnets=[$ECR_SUBNETS],securityGroups=[$ECR_SECURITY_GROUP],assignPublicIp=ENABLED}" \
|
||||
--tags key=pr,value=$PR_NUMBER key=github_user,value=${{ github.actor }}
|
||||
- name: Deploy Amazon ECS task definition
|
||||
id: deploy-task
|
||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v2
|
||||
with:
|
||||
task-definition: ${{ steps.task-def.outputs.task-definition }}
|
||||
service: pr-${{ github.event.inputs.issue_number || github.event.pull_request.number }}-service
|
||||
cluster: superset-ci
|
||||
wait-for-service-stability: true
|
||||
wait-for-minutes: 10
|
||||
|
||||
- name: List tasks
|
||||
id: list-tasks
|
||||
run: |
|
||||
echo "task=$(aws ecs list-tasks --cluster superset-ci --service-name pr-${{ github.event.inputs.issue_number || github.event.pull_request.number }}-service | jq '.taskArns | first')" >> $GITHUB_OUTPUT
|
||||
- name: Get network interface
|
||||
id: get-eni
|
||||
run: |
|
||||
echo "eni=$(aws ecs describe-tasks --cluster superset-ci --tasks ${{ steps.list-tasks.outputs.task }} | jq '.tasks[0].attachments[0].details | map(select(.name=="networkInterfaceId"))[0].value')" >> $GITHUB_OUTPUT
|
||||
- name: Get public IP
|
||||
id: get-ip
|
||||
run: |
|
||||
echo "ip=$(aws ec2 describe-network-interfaces --network-interface-ids ${{ steps.get-eni.outputs.eni }} | jq -r '.NetworkInterfaces | first | .Association.PublicIp')" >> $GITHUB_OUTPUT
|
||||
- name: Comment (success)
|
||||
if: ${{ success() }}
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{github.token}}
|
||||
script: |
|
||||
const issue_number = context.payload.inputs?.issue_number || context.issue.number;
|
||||
github.rest.issues.createComment({
|
||||
issue_number: issue_number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: `@${{ github.actor }} Ephemeral environment spinning up at http://${{ steps.get-ip.outputs.ip }}:8080. Credentials are 'admin'/'admin'. Please allow several minutes for bootstrapping and startup.`
|
||||
});
|
||||
- name: Comment (failure)
|
||||
if: ${{ failure() }}
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{github.token}}
|
||||
script: |
|
||||
const issue_number = context.payload.inputs?.issue_number || context.issue.number;
|
||||
github.rest.issues.createComment({
|
||||
issue_number: issue_number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: '@${{ github.event.inputs.user_login || github.event.comment.user.login }} Ephemeral environment creation failed. Please check the Actions logs for details.'
|
||||
})
|
||||
11
.github/workflows/generate-FOSSA-report.yml
vendored
11
.github/workflows/generate-FOSSA-report.yml
vendored
@@ -6,9 +6,6 @@ on:
|
||||
- "master"
|
||||
- "[0-9].[0-9]*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -19,12 +16,10 @@ jobs:
|
||||
id: check
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${FOSSA_API_KEY}" ]; then
|
||||
if [ -n "${{ (secrets.FOSSA_API_KEY != '' ) || '' }}" ]; then
|
||||
echo "has-secrets=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
env:
|
||||
FOSSA_API_KEY: ${{ (secrets.FOSSA_API_KEY != '' ) || '' }}
|
||||
license_check:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
@@ -32,12 +27,12 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "11"
|
||||
|
||||
25
.github/workflows/github-action-validator.yml
vendored
25
.github/workflows/github-action-validator.yml
vendored
@@ -6,34 +6,18 @@ on:
|
||||
- "master"
|
||||
- "[0-9].[0-9]*"
|
||||
pull_request:
|
||||
branches:
|
||||
- "**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
jobs:
|
||||
|
||||
validate-all-ghas:
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
# Required for the zizmor action to upload its SARIF results to
|
||||
# GitHub code scanning (advanced-security is enabled by default).
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
@@ -42,6 +26,3 @@ jobs:
|
||||
|
||||
- name: Run Script
|
||||
run: bash .github/workflows/github-action-validator.sh
|
||||
|
||||
- name: Check for security issues on GHA workflows
|
||||
uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6
|
||||
|
||||
2
.github/workflows/issue_creation.yml
vendored
2
.github/workflows/issue_creation.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
7
.github/workflows/labeler.yml
vendored
7
.github/workflows/labeler.yml
vendored
@@ -2,11 +2,6 @@ name: "Pull Request Labeler"
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
permissions:
|
||||
@@ -14,7 +9,7 @@ jobs:
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
sync-labels: true
|
||||
|
||||
|
||||
8
.github/workflows/latest-release-tag.yml
vendored
8
.github/workflows/latest-release-tag.yml
vendored
@@ -12,17 +12,15 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Check for latest tag
|
||||
id: latest-tag
|
||||
env:
|
||||
RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
source ./scripts/tag_latest_release.sh "$RELEASE_TAG_NAME" --dry-run
|
||||
source ./scripts/tag_latest_release.sh $(echo ${{ github.event.release.tag_name }}) --dry-run
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
@@ -31,7 +29,7 @@ jobs:
|
||||
|
||||
- name: Run latest-tag
|
||||
uses: ./.github/actions/latest-tag
|
||||
if: steps.latest-tag.outputs.SKIP_TAG != 'true'
|
||||
if: (! ${{ steps.latest-tag.outputs.SKIP_TAG }} )
|
||||
with:
|
||||
description: Superset latest release
|
||||
tag-name: latest
|
||||
|
||||
7
.github/workflows/license-check.yml
vendored
7
.github/workflows/license-check.yml
vendored
@@ -4,9 +4,6 @@ on:
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
@@ -18,12 +15,12 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
|
||||
12
.github/workflows/no-hold-label.yml
vendored
12
.github/workflows/no-hold-label.yml
vendored
@@ -4,23 +4,17 @@ on:
|
||||
pull_request:
|
||||
types: [labeled, unlabeled, opened, reopened, synchronize]
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
|
||||
# Let each label event run to completion. Cancelling in-progress runs leaves
|
||||
# CANCELLED entries in the PR's check-suite rollup, which poisons GitHub's
|
||||
# `status:success` search filter even though all real CI passed. The job is
|
||||
# a tiny no-op github-script call, so the wasted compute is negligible.
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: false
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
check-hold-label:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Check for 'hold' label
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
script: |
|
||||
|
||||
7
.github/workflows/pr-lint.yml
vendored
7
.github/workflows/pr-lint.yml
vendored
@@ -8,11 +8,6 @@ on:
|
||||
# Possible values: https://help.github.com/en/actions/reference/events-that-trigger-workflows#pull-request-event-pull_request
|
||||
types: [opened, edited, reopened, synchronize]
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint-check:
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -21,7 +16,7 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
33
.github/workflows/pre-commit.yml
vendored
33
.github/workflows/pre-commit.yml
vendored
@@ -8,9 +8,6 @@ on:
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
@@ -19,16 +16,12 @@ concurrency:
|
||||
jobs:
|
||||
pre-commit:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
matrix:
|
||||
# Run the full version spread on push (master/release) and nightly,
|
||||
# but only the current version on PRs — lint/format/type results
|
||||
# rarely differ across patch versions, so 3x per PR is wasteful.
|
||||
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["current", "previous", "next"]') }}
|
||||
python-version: ["current", "previous", "next"]
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
@@ -46,11 +39,9 @@ jobs:
|
||||
echo "HOMEBREW_REPOSITORY=$HOMEBREW_REPOSITORY" >>"${GITHUB_ENV}"
|
||||
brew install norwoodj/tap/helm-docs
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'superset-frontend/package-lock.json'
|
||||
|
||||
- name: Install Frontend Dependencies
|
||||
run: |
|
||||
@@ -63,34 +54,24 @@ jobs:
|
||||
yarn install --immutable
|
||||
|
||||
- name: Cache pre-commit environments
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pre-commit
|
||||
key: pre-commit-v2-${{ runner.os }}-py${{ matrix.python-version }}-${{ hashFiles('.pre-commit-config.yaml') }}
|
||||
restore-keys: |
|
||||
pre-commit-v2-${{ runner.os }}-py${{ matrix.python-version }}-
|
||||
|
||||
- name: Get changed files
|
||||
id: changed_files
|
||||
uses: ./.github/actions/file-changes-action
|
||||
with:
|
||||
output: ' '
|
||||
|
||||
- name: pre-commit
|
||||
env:
|
||||
CHANGED_FILES: ${{ steps.changed_files.outputs.files }}
|
||||
run: |
|
||||
set +e # Don't exit immediately on failure
|
||||
export SKIP=type-checking-frontend
|
||||
pre-commit run --files $CHANGED_FILES
|
||||
export SKIP=eslint-frontend,type-checking-frontend
|
||||
pre-commit run --all-files
|
||||
PRE_COMMIT_EXIT_CODE=$?
|
||||
git diff --quiet --exit-code
|
||||
GIT_DIFF_EXIT_CODE=$?
|
||||
if [ "${PRE_COMMIT_EXIT_CODE}" -ne 0 ] || [ "${GIT_DIFF_EXIT_CODE}" -ne 0 ]; then
|
||||
if [ "${PRE_COMMIT_EXIT_CODE}" -ne 0 ]; then
|
||||
echo "❌ Pre-commit check failed (exit code: ${PRE_COMMIT_EXIT_CODE})."
|
||||
echo "🔍 Modified files:"
|
||||
git diff --name-only
|
||||
echo "❌ Pre-commit check failed (exit code: ${EXIT_CODE})."
|
||||
else
|
||||
echo "❌ Git working directory is dirty."
|
||||
echo "📌 This likely means that pre-commit made changes that were not committed."
|
||||
|
||||
70
.github/workflows/prefer-typescript.yml
vendored
Normal file
70
.github/workflows/prefer-typescript.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
name: Prefer TypeScript
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "[0-9].[0-9]*"
|
||||
paths:
|
||||
- "superset-frontend/src/**"
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
paths:
|
||||
- "superset-frontend/src/**"
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
prefer_typescript:
|
||||
if: github.ref == 'ref/heads/master' && github.event_name == 'pull_request'
|
||||
name: Prefer TypeScript
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Get changed files
|
||||
id: changed
|
||||
uses: ./.github/actions/file-changes-action
|
||||
with:
|
||||
githubToken: ${{ github.token }}
|
||||
|
||||
- name: Determine if a .js or .jsx file was added
|
||||
id: check
|
||||
run: |
|
||||
js_files_added() {
|
||||
jq -r '
|
||||
map(
|
||||
select(
|
||||
endswith(".js") or endswith(".jsx")
|
||||
)
|
||||
) | join("\n")
|
||||
' ${HOME}/files_added.json
|
||||
}
|
||||
echo "js_files_added=$(js_files_added)" >> $GITHUB_OUTPUT
|
||||
|
||||
- if: steps.check.outputs.js_files_added
|
||||
name: Add Comment to PR
|
||||
uses: ./.github/actions/comment-on-pr
|
||||
continue-on-error: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
msg: |
|
||||
### WARNING: Prefer TypeScript
|
||||
|
||||
Looks like your PR contains new `.js` or `.jsx` files:
|
||||
|
||||
```
|
||||
${{steps.check.outputs.js_files_added}}
|
||||
```
|
||||
|
||||
As decided in [SIP-36](https://github.com/apache/superset/issues/9101), all new frontend code should be written in TypeScript. Please convert above files to TypeScript then re-request review.
|
||||
18
.github/workflows/release.yml
vendored
18
.github/workflows/release.yml
vendored
@@ -6,9 +6,6 @@ on:
|
||||
- "master"
|
||||
- "[0-9].[0-9]*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -19,23 +16,18 @@ jobs:
|
||||
id: check
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${NPM_TOKEN}" ]; then
|
||||
if [ -n "${{ (secrets.NPM_TOKEN != '' && secrets.GH_PERSONAL_ACCESS_TOKEN != '') || '' }}" ]; then
|
||||
echo "has-secrets=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
env:
|
||||
NPM_TOKEN: ${{ (secrets.NPM_TOKEN != '' && secrets.GH_PERSONAL_ACCESS_TOKEN != '') || '' }}
|
||||
build:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
name: Bump version and publish package(s)
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
# pulls all commits (needed for lerna / semantic release to correctly version)
|
||||
fetch-depth: 0
|
||||
- name: Get tags and filter trigger tags
|
||||
@@ -50,13 +42,13 @@ jobs:
|
||||
|
||||
- name: Install Node.js
|
||||
if: env.HAS_TAGS
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
|
||||
- name: Cache npm
|
||||
if: env.HAS_TAGS
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
@@ -70,7 +62,7 @@ jobs:
|
||||
run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
|
||||
- name: Cache npm
|
||||
if: env.HAS_TAGS
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
uses: actions/cache@v4
|
||||
id: npm-cache # use this to check for `cache-hit` (`steps.npm-cache.outputs.cache-hit != 'true'`)
|
||||
with:
|
||||
path: ${{ steps.npm-cache-dir-path.outputs.dir }}
|
||||
|
||||
18
.github/workflows/showtime-cleanup.yml
vendored
18
.github/workflows/showtime-cleanup.yml
vendored
@@ -7,6 +7,12 @@ on:
|
||||
|
||||
# Manual trigger for testing
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
max_age_hours:
|
||||
description: 'Maximum age in hours before cleanup'
|
||||
required: false
|
||||
default: '48'
|
||||
type: string
|
||||
|
||||
# Common environment variables
|
||||
env:
|
||||
@@ -32,5 +38,13 @@ jobs:
|
||||
|
||||
- name: Cleanup expired environments
|
||||
run: |
|
||||
echo "Cleaning up environments respecting TTL labels"
|
||||
python -m showtime cleanup --respect-ttl
|
||||
MAX_AGE="${{ github.event.inputs.max_age_hours || '48' }}"
|
||||
|
||||
# Validate max_age is numeric
|
||||
if [[ ! "$MAX_AGE" =~ ^[0-9]+$ ]]; then
|
||||
echo "❌ Invalid max_age_hours format: $MAX_AGE (must be numeric)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Cleaning up environments older than ${MAX_AGE}h"
|
||||
python -m showtime cleanup --older-than "${MAX_AGE}h"
|
||||
|
||||
47
.github/workflows/showtime-trigger.yml
vendored
47
.github/workflows/showtime-trigger.yml
vendored
@@ -2,7 +2,6 @@ name: 🎪 Superset Showtime
|
||||
|
||||
# Ultra-simple: just sync on any PR state change
|
||||
on:
|
||||
# zizmor: ignore[dangerous-triggers] - required to react to PR label changes; this workflow does not check out or execute PR-provided code
|
||||
pull_request_target:
|
||||
types: [labeled, unlabeled, synchronize, closed]
|
||||
|
||||
@@ -38,7 +37,7 @@ jobs:
|
||||
steps:
|
||||
- name: Security Check - Authorize Maintainers Only
|
||||
id: auth
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
@@ -62,8 +61,17 @@ jobs:
|
||||
console.log(`📊 Permission level for ${actor}: ${permission.permission}`);
|
||||
const authorized = ['write', 'admin'].includes(permission.permission);
|
||||
|
||||
// If this is a synchronize event from unauthorized user, check if Showtime is active and set blocked label
|
||||
if (!authorized && context.eventName === 'pull_request_target' && context.payload.action === 'synchronize') {
|
||||
if (!authorized) {
|
||||
console.log(`🚨 Unauthorized user ${actor} - skipping all operations`);
|
||||
core.setOutput('authorized', 'false');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`✅ Authorized maintainer: ${actor}`);
|
||||
core.setOutput('authorized', 'true');
|
||||
|
||||
// If this is a synchronize event, check if Showtime is active and set blocked label
|
||||
if (context.eventName === 'pull_request_target' && context.payload.action === 'synchronize') {
|
||||
console.log(`🔒 Synchronize event detected - checking if Showtime is active`);
|
||||
|
||||
// Check if PR has any circus tent labels (Showtime is in use)
|
||||
@@ -91,24 +99,13 @@ jobs:
|
||||
}
|
||||
}
|
||||
|
||||
if (!authorized) {
|
||||
console.log(`🚨 Unauthorized user ${actor} - skipping all operations`);
|
||||
core.setOutput('authorized', 'false');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`✅ Authorized maintainer: ${actor}`);
|
||||
core.setOutput('authorized', 'true');
|
||||
|
||||
- name: Install Superset Showtime
|
||||
if: steps.auth.outputs.authorized == 'true'
|
||||
run: |
|
||||
echo "::notice::Maintainer $GITHUB_ACTOR triggered deploy for PR ${PULL_REQUEST_NUMBER}"
|
||||
echo "::notice::Maintainer ${{ github.actor }} triggered deploy for PR ${{ github.event.pull_request.number || github.event.inputs.pr_number }}"
|
||||
pip install --upgrade superset-showtime
|
||||
showtime version
|
||||
|
||||
env:
|
||||
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number || github.event.inputs.pr_number }}
|
||||
- name: Check what actions are needed
|
||||
if: steps.auth.outputs.authorized == 'true'
|
||||
id: check
|
||||
@@ -116,14 +113,12 @@ jobs:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
INPUT_PR_NUMBER: ${{ github.event.inputs.pr_number }}
|
||||
INPUT_SHA: ${{ github.event.inputs.sha }}
|
||||
run: |
|
||||
# Bulletproof PR number extraction
|
||||
if [[ -n "${{ github.event.pull_request.number }}" ]]; then
|
||||
PR_NUM="${{ github.event.pull_request.number }}"
|
||||
elif [[ -n "${INPUT_PR_NUMBER}" ]]; then
|
||||
PR_NUM="${INPUT_PR_NUMBER}"
|
||||
elif [[ -n "${{ github.event.inputs.pr_number }}" ]]; then
|
||||
PR_NUM="${{ github.event.inputs.pr_number }}"
|
||||
else
|
||||
echo "❌ No PR number found in event or inputs"
|
||||
exit 1
|
||||
@@ -132,8 +127,8 @@ jobs:
|
||||
echo "Using PR number: $PR_NUM"
|
||||
|
||||
# Run sync check-only with optional SHA override
|
||||
if [[ -n "${INPUT_SHA}" ]]; then
|
||||
OUTPUT=$(python -m showtime sync $PR_NUM --check-only --sha "${INPUT_SHA}")
|
||||
if [[ -n "${{ github.event.inputs.sha }}" ]]; then
|
||||
OUTPUT=$(python -m showtime sync $PR_NUM --check-only --sha "${{ github.event.inputs.sha }}")
|
||||
else
|
||||
OUTPUT=$(python -m showtime sync $PR_NUM --check-only)
|
||||
fi
|
||||
@@ -152,7 +147,7 @@ jobs:
|
||||
|
||||
- name: Checkout PR code (only if build needed)
|
||||
if: steps.auth.outputs.authorized == 'true' && steps.check.outputs.build_needed == 'true'
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ steps.check.outputs.target_sha }}
|
||||
persist-credentials: false
|
||||
@@ -174,11 +169,9 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
|
||||
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
CHECK_PR_NUMBER: ${{ steps.check.outputs.pr_number }}
|
||||
CHECK_TARGET_SHA: ${{ steps.check.outputs.target_sha }}
|
||||
run: |
|
||||
PR_NUM="$CHECK_PR_NUMBER"
|
||||
TARGET_SHA="$CHECK_TARGET_SHA"
|
||||
PR_NUM="${{ steps.check.outputs.pr_number }}"
|
||||
TARGET_SHA="${{ steps.check.outputs.target_sha }}"
|
||||
if [[ -n "$TARGET_SHA" ]]; then
|
||||
python -m showtime sync $PR_NUM --sha "$TARGET_SHA"
|
||||
else
|
||||
|
||||
8
.github/workflows/superset-app-cli.yml
vendored
8
.github/workflows/superset-app-cli.yml
vendored
@@ -8,10 +8,6 @@ on:
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
@@ -27,7 +23,7 @@ jobs:
|
||||
SUPERSET__SQLALCHEMY_DATABASE_URI: postgresql+psycopg2://superset:superset@127.0.0.1:15432/superset
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
POSTGRES_USER: superset
|
||||
POSTGRES_PASSWORD: superset
|
||||
@@ -41,7 +37,7 @@ jobs:
|
||||
- 16379:6379
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
91
.github/workflows/superset-applitool-cypress.yml
vendored
Normal file
91
.github/workflows/superset-applitool-cypress.yml
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
name: Applitools Cypress
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 1 * * *"
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
has-secrets: ${{ steps.check.outputs.has-secrets }}
|
||||
steps:
|
||||
- name: "Check for secrets"
|
||||
id: check
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${{ (secrets.APPLITOOLS_API_KEY != '' && secrets.APPLITOOLS_API_KEY != '') || '' }}" ]; then
|
||||
echo "has-secrets=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
cypress-applitools:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
browser: ["chrome"]
|
||||
env:
|
||||
SUPERSET_ENV: development
|
||||
SUPERSET_CONFIG: tests.integration_tests.superset_test_config
|
||||
SUPERSET__SQLALCHEMY_DATABASE_URI: postgresql+psycopg2://superset:superset@127.0.0.1:15432/superset
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
REDIS_PORT: 16379
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
APPLITOOLS_APP_NAME: Superset
|
||||
APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }}
|
||||
APPLITOOLS_BATCH_ID: ${{ github.sha }}
|
||||
APPLITOOLS_BATCH_NAME: Superset Cypress
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
POSTGRES_USER: superset
|
||||
POSTGRES_PASSWORD: superset
|
||||
ports:
|
||||
- 15432:5432
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- 16379:6379
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
ref: master
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
- name: Import test data
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: testdata
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
- name: Install npm dependencies
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: npm-install
|
||||
- name: Build javascript packages
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: build-instrumented-assets
|
||||
- name: Setup Postgres
|
||||
if: steps.check.outcome == 'failure'
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: setup-postgres
|
||||
- name: Install cypress
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: cypress-install
|
||||
- name: Run Cypress
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
env:
|
||||
CYPRESS_BROWSER: ${{ matrix.browser }}
|
||||
with:
|
||||
run: cypress-run-applitools
|
||||
52
.github/workflows/superset-applitools-storybook.yml
vendored
Normal file
52
.github/workflows/superset-applitools-storybook.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
name: Applitools Storybook
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
env:
|
||||
APPLITOOLS_APP_NAME: Superset
|
||||
APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }}
|
||||
APPLITOOLS_BATCH_ID: ${{ github.sha }}
|
||||
APPLITOOLS_BATCH_NAME: Superset Storybook
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
has-secrets: ${{ steps.check.outputs.has-secrets }}
|
||||
steps:
|
||||
- name: "Check for secrets"
|
||||
id: check
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${{ (secrets.APPLITOOLS_API_KEY != '' && secrets.APPLITOOLS_API_KEY != '') || '' }}" ]; then
|
||||
echo "has-secrets=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
cron:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
ref: master
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
- name: Install eyes-storybook dependencies
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: eyes-storybook-dependencies
|
||||
- name: Install NPM dependencies
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: npm-install
|
||||
- name: Run Applitools Eyes-Storybook
|
||||
working-directory: ./superset-frontend
|
||||
run: npx eyes-storybook -u https://superset-storybook.netlify.app/
|
||||
73
.github/workflows/superset-docs-deploy.yml
vendored
73
.github/workflows/superset-docs-deploy.yml
vendored
@@ -1,14 +1,6 @@
|
||||
name: Docs Deployment
|
||||
|
||||
on:
|
||||
# Deploy after integration tests complete on master
|
||||
# zizmor: ignore[dangerous-triggers] - runs in base-branch context after a trusted upstream workflow; scoped to master
|
||||
workflow_run:
|
||||
workflows: ["Python-Integration"]
|
||||
types: [completed]
|
||||
branches: [master]
|
||||
|
||||
# Also allow manual trigger and direct pushes to docs
|
||||
push:
|
||||
paths:
|
||||
- "docs/**"
|
||||
@@ -18,19 +10,6 @@ on:
|
||||
|
||||
workflow_dispatch: {}
|
||||
|
||||
# Serialize deploys: the action pushes to apache/superset-site without
|
||||
# rebasing, so concurrent runs race on the final push and the loser fails
|
||||
# with `! [rejected] asf-site -> asf-site (fetch first)`. Cancel any
|
||||
# in-progress run as soon as a newer one starts — the destination repo
|
||||
# isn't touched until the final push step, so canceling mid-build is safe,
|
||||
# and the freshest content always wins.
|
||||
concurrency:
|
||||
group: docs-deploy-asf-site
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -41,37 +20,28 @@ jobs:
|
||||
id: check
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${SUPERSET_SITE_BUILD}" ]; then
|
||||
if [ -n "${{ (secrets.SUPERSET_SITE_BUILD != '' && secrets.SUPERSET_SITE_BUILD != '') || '' }}" ]; then
|
||||
echo "has-secrets=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
env:
|
||||
SUPERSET_SITE_BUILD: ${{ (secrets.SUPERSET_SITE_BUILD != '' && secrets.SUPERSET_SITE_BUILD != '') || '' }}
|
||||
build-deploy:
|
||||
needs: config
|
||||
# For workflow_run triggers, only deploy when the triggering run originated
|
||||
# from this repository (not a fork), ensuring the checked-out code and any
|
||||
# local actions executed with deploy credentials are trusted.
|
||||
if: >-
|
||||
needs.config.outputs.has-secrets &&
|
||||
(github.event_name != 'workflow_run' ||
|
||||
github.event.workflow_run.head_repository.full_name == github.repository)
|
||||
if: needs.config.outputs.has-secrets
|
||||
name: Build & Deploy
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.event.workflow_run.head_sha || github.sha }}"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './docs/.nvmrc'
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: '21'
|
||||
@@ -88,35 +58,6 @@ jobs:
|
||||
working-directory: docs
|
||||
run: |
|
||||
yarn install --check-cache
|
||||
- name: Download database diagnostics (if triggered by integration tests)
|
||||
if: github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success'
|
||||
uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21
|
||||
continue-on-error: true
|
||||
with:
|
||||
workflow: superset-python-integrationtest.yml
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
name: database-diagnostics
|
||||
path: docs/src/data/
|
||||
- name: Try to download latest diagnostics (for push/dispatch triggers)
|
||||
if: github.event_name != 'workflow_run'
|
||||
uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21
|
||||
continue-on-error: true
|
||||
with:
|
||||
workflow: superset-python-integrationtest.yml
|
||||
name: database-diagnostics
|
||||
path: docs/src/data/
|
||||
branch: master
|
||||
search_artifacts: true
|
||||
if_no_artifact_found: warn
|
||||
- name: Use diagnostics artifact if available
|
||||
working-directory: docs
|
||||
run: |
|
||||
if [ -f "src/data/databases-diagnostics.json" ]; then
|
||||
echo "Using fresh diagnostics from integration tests"
|
||||
mv src/data/databases-diagnostics.json src/data/databases.json
|
||||
else
|
||||
echo "Using committed databases.json (no artifact found)"
|
||||
fi
|
||||
- name: yarn build
|
||||
working-directory: docs
|
||||
run: |
|
||||
@@ -130,5 +71,5 @@ jobs:
|
||||
destination-github-username: "apache"
|
||||
destination-repository-name: "superset-site"
|
||||
target-branch: "asf-site"
|
||||
commit-message: "deploying docs: ${{ github.event.head_commit.message || 'triggered by integration tests' }} (apache/superset@${{ github.event.workflow_run.head_sha || github.sha }})"
|
||||
commit-message: "deploying docs: ${{ github.event.head_commit.message }} (apache/superset@${{ github.sha }})"
|
||||
user-email: dev@superset.apache.org
|
||||
|
||||
103
.github/workflows/superset-docs-verify.yml
vendored
103
.github/workflows/superset-docs-verify.yml
vendored
@@ -4,43 +4,29 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "docs/**"
|
||||
- "superset/db_engine_specs/**"
|
||||
- ".github/workflows/superset-docs-verify.yml"
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
# zizmor: ignore[dangerous-triggers] - runs in base-branch context and only consumes artifacts from the trusted upstream workflow
|
||||
workflow_run:
|
||||
workflows: ["Python-Integration"]
|
||||
types: [completed]
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.workflow_run.head_sha || github.run_id }}
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
linkinator:
|
||||
# See docs here: https://github.com/marketplace/actions/linkinator
|
||||
# Only run on pull_request, not workflow_run
|
||||
if: github.event_name == 'pull_request'
|
||||
name: Link Checking
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/checkout@v5
|
||||
# Do not bump this linkinator-action version without opening
|
||||
# an ASF Infra ticket to allow the new version first!
|
||||
- uses: JustinBeckwith/linkinator-action@af984b9f30f63e796ae2ea5be5e07cb587f1bbd9 # v2.3
|
||||
- uses: JustinBeckwith/linkinator-action@v1.11.0
|
||||
continue-on-error: true # This will make the job advisory (non-blocking, no red X)
|
||||
with:
|
||||
paths: "**/*.md, **/*.mdx"
|
||||
paths: "**/*.md, **/*.mdx, !superset-frontend/CHANGELOG.md"
|
||||
linksToSkip: >-
|
||||
^https://github.com/apache/(superset|incubator-superset)/(pull|issues)/\d+,
|
||||
^https://github.com/apache/(superset|incubator-superset)/commit/[a-f0-9]+,
|
||||
superset-frontend/.*CHANGELOG\.md,
|
||||
^https://github.com/apache/(superset|incubator-superset)/(pull|issue)/\d+,
|
||||
http://localhost:8088/,
|
||||
http://127.0.0.1:3000/,
|
||||
http://localhost:9001/,
|
||||
@@ -55,91 +41,32 @@ jobs:
|
||||
http://theiconic.com.au/,
|
||||
https://dev.mysql.com/doc/refman/5.7/en/innodb-limits.html,
|
||||
^https://img\.shields\.io/.*,
|
||||
https://vkusvill.ru/,
|
||||
https://www.linkedin.com/in/mark-thomas-b16751158/,
|
||||
https://theiconic.com.au/,
|
||||
https://wattbewerb.de/,
|
||||
https://timbr.ai/,
|
||||
https://opensource.org/license/apache-2-0,
|
||||
https://vkusvill.ru/
|
||||
https://www.linkedin.com/in/mark-thomas-b16751158/
|
||||
https://theiconic.com.au/
|
||||
https://wattbewerb.de/
|
||||
https://timbr.ai/
|
||||
https://opensource.org/license/apache-2-0
|
||||
https://www.plaidcloud.com/
|
||||
|
||||
build-on-pr:
|
||||
# Build docs when PR changes docs/** (uses committed databases.json)
|
||||
if: github.event_name == 'pull_request'
|
||||
name: Build (PR trigger)
|
||||
build-deploy:
|
||||
name: Build & Deploy
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: docs
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './docs/.nvmrc'
|
||||
- name: yarn install
|
||||
run: |
|
||||
yarn install --check-cache
|
||||
- name: Lint docs links
|
||||
# Fast source-level check for bare relative internal links
|
||||
# like `[Foo](../foo)` that Docusaurus's onBrokenLinks
|
||||
# setting can't catch. Runs in seconds; fails fast before
|
||||
# the expensive build step.
|
||||
run: |
|
||||
yarn lint:docs-links
|
||||
- name: yarn typecheck
|
||||
run: |
|
||||
yarn typecheck
|
||||
- name: yarn build
|
||||
run: |
|
||||
yarn build
|
||||
|
||||
build-after-tests:
|
||||
# Build docs after integration tests complete (uses fresh diagnostics)
|
||||
# Only runs if integration tests succeeded
|
||||
if: >
|
||||
github.event_name == 'workflow_run' &&
|
||||
github.event.workflow_run.conclusion == 'success' &&
|
||||
github.event.workflow_run.head_repository.full_name == github.repository
|
||||
name: Build (after integration tests)
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: docs
|
||||
steps:
|
||||
- name: "Checkout PR head: ${{ github.event.workflow_run.head_sha }}"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
ref: ${{ github.event.workflow_run.head_sha }}
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: './docs/.nvmrc'
|
||||
- name: yarn install
|
||||
run: |
|
||||
yarn install --check-cache
|
||||
- name: Download database diagnostics from integration tests
|
||||
uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21
|
||||
with:
|
||||
workflow: superset-python-integrationtest.yml
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
name: database-diagnostics
|
||||
path: docs/src/data/
|
||||
if_no_artifact_found: 'warning'
|
||||
- name: Use fresh diagnostics
|
||||
run: |
|
||||
if [ -f "src/data/databases-diagnostics.json" ]; then
|
||||
echo "Using fresh diagnostics from integration tests"
|
||||
mv src/data/databases-diagnostics.json src/data/databases.json
|
||||
else
|
||||
echo "Warning: No diagnostics artifact found, using committed data"
|
||||
fi
|
||||
- name: yarn typecheck
|
||||
run: |
|
||||
yarn typecheck
|
||||
|
||||
236
.github/workflows/superset-e2e.yml
vendored
236
.github/workflows/superset-e2e.yml
vendored
@@ -27,32 +27,9 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
outputs:
|
||||
python: ${{ steps.check.outputs.python }}
|
||||
frontend: ${{ steps.check.outputs.frontend }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
cypress-matrix:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
|
||||
# Somehow one test flakes on 24.04 for unknown reasons, this is the only GHA left on 22.04
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
@@ -63,14 +40,9 @@ jobs:
|
||||
# https://github.com/cypress-io/github-action/issues/48
|
||||
fail-fast: false
|
||||
matrix:
|
||||
parallel_id: [0, 1]
|
||||
parallel_id: [0, 1, 2, 3, 4, 5]
|
||||
browser: ["chrome"]
|
||||
app_root: ${{ github.event_name == 'push' && fromJSON('["", "/app/prefix"]') || fromJSON('[""]') }}
|
||||
# The /app/prefix variant (push events only) is smoke-tested on a single
|
||||
# shard rather than the full matrix, so exclude it from the other shards.
|
||||
exclude:
|
||||
- parallel_id: 1
|
||||
app_root: "/app/prefix"
|
||||
app_root: ["", "/app/prefix"]
|
||||
env:
|
||||
SUPERSET_ENV: development
|
||||
SUPERSET_CONFIG: tests.integration_tests.superset_test_config
|
||||
@@ -82,7 +54,7 @@ jobs:
|
||||
USE_DASHBOARD: ${{ github.event.inputs.use_dashboard == 'true' || 'false' }}
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
POSTGRES_USER: superset
|
||||
POSTGRES_PASSWORD: superset
|
||||
@@ -97,60 +69,71 @@ jobs:
|
||||
# Conditional checkout based on context
|
||||
- name: Checkout for push or pull_request event
|
||||
if: github.event_name == 'push' || github.event_name == 'pull_request'
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
||||
- name: Checkout using ref (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != ''
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ github.event.inputs.ref }}
|
||||
submodules: recursive
|
||||
- name: Checkout using PR ID (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != ''
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
|
||||
submodules: recursive
|
||||
# -------------------------------------------------------
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
if: steps.check.outputs.python || steps.check.outputs.frontend
|
||||
- name: Setup postgres
|
||||
if: steps.check.outputs.python || steps.check.outputs.frontend
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: setup-postgres
|
||||
- name: Import test data
|
||||
if: steps.check.outputs.python || steps.check.outputs.frontend
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: testdata
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
if: steps.check.outputs.python || steps.check.outputs.frontend
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'superset-frontend/package-lock.json'
|
||||
- name: Install npm dependencies
|
||||
if: steps.check.outputs.python || steps.check.outputs.frontend
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: npm-install
|
||||
- name: Build javascript packages
|
||||
if: steps.check.outputs.python || steps.check.outputs.frontend
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: build-instrumented-assets
|
||||
- name: Install cypress
|
||||
if: steps.check.outputs.python || steps.check.outputs.frontend
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: cypress-install
|
||||
- name: Run Cypress
|
||||
if: steps.check.outputs.python || steps.check.outputs.frontend
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
env:
|
||||
CYPRESS_BROWSER: ${{ matrix.browser }}
|
||||
PARALLEL_ID: ${{ matrix.parallel_id }}
|
||||
PARALLELISM: 2
|
||||
PARALLELISM: 6
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
NODE_OPTIONS: "--max-old-space-size=4096"
|
||||
with:
|
||||
@@ -158,186 +141,13 @@ jobs:
|
||||
- name: Set safe app root
|
||||
if: failure()
|
||||
id: set-safe-app-root
|
||||
env:
|
||||
APP_ROOT: ${{ matrix.app_root }}
|
||||
run: |
|
||||
APP_ROOT="${{ matrix.app_root }}"
|
||||
SAFE_APP_ROOT=${APP_ROOT//\//_}
|
||||
echo "safe_app_root=$SAFE_APP_ROOT" >> $GITHUB_OUTPUT
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
path: ${{ github.workspace }}/superset-frontend/cypress-base/cypress/screenshots
|
||||
name: cypress-artifact-${{ github.run_id }}-${{ github.job }}-${{ matrix.browser }}-${{ matrix.parallel_id }}--${{ steps.set-safe-app-root.outputs.safe_app_root }}
|
||||
|
||||
playwright-tests:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
browser: ["chromium"]
|
||||
app_root: ${{ github.event_name == 'push' && fromJSON('["", "/app/prefix"]') || fromJSON('[""]') }}
|
||||
env:
|
||||
SUPERSET_ENV: development
|
||||
SUPERSET_CONFIG: tests.integration_tests.superset_test_config
|
||||
SUPERSET__SQLALCHEMY_DATABASE_URI: postgresql+psycopg2://superset:superset@127.0.0.1:15432/superset
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
REDIS_PORT: 16379
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
env:
|
||||
POSTGRES_USER: superset
|
||||
POSTGRES_PASSWORD: superset
|
||||
ports:
|
||||
- 15432:5432
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- 16379:6379
|
||||
steps:
|
||||
# -------------------------------------------------------
|
||||
# Conditional checkout based on context (same as Cypress workflow)
|
||||
- name: Checkout for push or pull_request event
|
||||
if: github.event_name == 'push' || github.event_name == 'pull_request'
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
||||
- name: Checkout using ref (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != ''
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ github.event.inputs.ref }}
|
||||
submodules: recursive
|
||||
- name: Checkout using PR ID (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != ''
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
|
||||
submodules: recursive
|
||||
# -------------------------------------------------------
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
- name: Setup postgres
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: setup-postgres
|
||||
- name: Import test data
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: playwright_testdata
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'superset-frontend/package-lock.json'
|
||||
- name: Install npm dependencies
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: npm-install
|
||||
- name: Build javascript packages
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: build-instrumented-assets
|
||||
- name: Build embedded SDK
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: build-embedded-sdk
|
||||
- name: Install Playwright
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: playwright-install
|
||||
- name: Run Playwright (Required Tests)
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
env:
|
||||
NODE_OPTIONS: "--max-old-space-size=4096"
|
||||
with:
|
||||
run: playwright-run "${{ matrix.app_root }}"
|
||||
- name: Set safe app root
|
||||
if: failure()
|
||||
id: set-safe-app-root
|
||||
env:
|
||||
APP_ROOT: ${{ matrix.app_root }}
|
||||
run: |
|
||||
SAFE_APP_ROOT=${APP_ROOT//\//_}
|
||||
echo "safe_app_root=$SAFE_APP_ROOT" >> $GITHUB_OUTPUT
|
||||
- name: Upload Playwright Artifacts
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
if: failure()
|
||||
with:
|
||||
path: |
|
||||
${{ github.workspace }}/superset-frontend/playwright-results/
|
||||
${{ github.workspace }}/superset-frontend/test-results/
|
||||
name: playwright-artifact-${{ github.run_id }}-${{ github.job }}-${{ matrix.browser }}--${{ steps.set-safe-app-root.outputs.safe_app_root }}
|
||||
|
||||
# Stable required-status-check anchors. cypress-matrix and playwright-tests
|
||||
# are matrix jobs gated on change detection (python || frontend). On a PR
|
||||
# that touches neither — e.g. a docs-only PR — they are skipped at the job
|
||||
# level, which happens before matrix expansion, so the per-combination
|
||||
# contexts (`cypress-matrix (0, chrome)`, `playwright-tests (chromium)`) are
|
||||
# never produced and branch protection waits on them forever. These
|
||||
# always-running jobs report a single stable context that passes when the
|
||||
# underlying matrix job succeeded or was skipped, and fails only on a real
|
||||
# failure. Require these in .asf.yaml instead of the matrix-expanded names.
|
||||
#
|
||||
# A matrix job reads as "skipped" in two distinct cases, and only the first
|
||||
# is a legitimate pass: (a) change detection succeeded and gated the job off
|
||||
# (docs-only PR); (b) the `changes` job itself failed or was cancelled, in
|
||||
# which case GHA skips its dependents too. Accepting (b) would let a broken
|
||||
# change-detector report a false green, so each anchor first requires
|
||||
# `changes` to have succeeded before honouring a skip.
|
||||
cypress-matrix-required:
|
||||
needs: [changes, cypress-matrix]
|
||||
if: always()
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
permissions: {}
|
||||
steps:
|
||||
- name: Check cypress-matrix result
|
||||
env:
|
||||
CHANGES: ${{ needs.changes.result }}
|
||||
RESULT: ${{ needs.cypress-matrix.result }}
|
||||
run: |
|
||||
if [ "$CHANGES" != "success" ]; then
|
||||
echo "change detection did not succeed (result: $CHANGES); refusing to pass on a skipped matrix"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$RESULT" != "success" ] && [ "$RESULT" != "skipped" ]; then
|
||||
echo "cypress-matrix did not pass (result: $RESULT)"
|
||||
exit 1
|
||||
fi
|
||||
echo "cypress-matrix result: $RESULT (changes: $CHANGES)"
|
||||
|
||||
playwright-tests-required:
|
||||
needs: [changes, playwright-tests]
|
||||
if: always()
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
permissions: {}
|
||||
steps:
|
||||
- name: Check playwright-tests result
|
||||
env:
|
||||
CHANGES: ${{ needs.changes.result }}
|
||||
RESULT: ${{ needs.playwright-tests.result }}
|
||||
run: |
|
||||
if [ "$CHANGES" != "success" ]; then
|
||||
echo "change detection did not succeed (result: $CHANGES); refusing to pass on a skipped matrix"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$RESULT" != "success" ] && [ "$RESULT" != "skipped" ]; then
|
||||
echo "playwright-tests did not pass (result: $RESULT)"
|
||||
exit 1
|
||||
fi
|
||||
echo "playwright-tests result: $RESULT (changes: $CHANGES)"
|
||||
|
||||
15
.github/workflows/superset-extensions-cli.yml
vendored
15
.github/workflows/superset-extensions-cli.yml
vendored
@@ -8,10 +8,6 @@ on:
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
@@ -20,18 +16,15 @@ concurrency:
|
||||
jobs:
|
||||
test-superset-extensions-cli-package:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
matrix:
|
||||
# Full version spread on push (master/release) + nightly; current only
|
||||
# on PRs to cut runner cost (cross-version breaks are caught at merge).
|
||||
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["previous", "current", "next"]') }}
|
||||
python-version: ["previous", "current", "next"]
|
||||
defaults:
|
||||
run:
|
||||
working-directory: superset-extensions-cli
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
@@ -56,7 +49,7 @@ jobs:
|
||||
|
||||
- name: Upload coverage reports to Codecov
|
||||
if: steps.check.outputs.superset-extensions-cli
|
||||
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
file: ./coverage.xml
|
||||
flags: superset-extensions-cli
|
||||
@@ -65,7 +58,7 @@ jobs:
|
||||
|
||||
- name: Upload HTML coverage report
|
||||
if: steps.check.outputs.superset-extensions-cli
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: superset-extensions-cli-coverage-html
|
||||
path: htmlcov/
|
||||
|
||||
84
.github/workflows/superset-frontend.yml
vendored
84
.github/workflows/superset-frontend.yml
vendored
@@ -16,18 +16,14 @@ concurrency:
|
||||
env:
|
||||
TAG: apache/superset:GHA-${{ github.run_id }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
frontend-build:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
outputs:
|
||||
should-run: ${{ steps.check.outputs.frontend }}
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
@@ -58,14 +54,14 @@ jobs:
|
||||
- name: Save Docker Image as Artifact
|
||||
if: steps.check.outputs.frontend
|
||||
run: |
|
||||
docker save $TAG | zstd -3 --threads=0 > docker-image.tar.zst
|
||||
docker save $TAG | gzip > docker-image.tar.gz
|
||||
|
||||
- name: Upload Docker Image Artifact
|
||||
if: steps.check.outputs.frontend
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: docker-image
|
||||
path: docker-image.tar.zst
|
||||
path: docker-image.tar.gz
|
||||
|
||||
sharded-jest-tests:
|
||||
needs: frontend-build
|
||||
@@ -75,16 +71,14 @@ jobs:
|
||||
shard: [1, 2, 3, 4, 5, 6, 7, 8]
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Download Docker Image Artifact
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: docker-image
|
||||
|
||||
- name: Load Docker Image
|
||||
run: |
|
||||
zstd -d < docker-image.tar.zst | docker load
|
||||
run: docker load < docker-image.tar.gz
|
||||
|
||||
- name: npm run test with coverage
|
||||
run: |
|
||||
@@ -93,10 +87,10 @@ jobs:
|
||||
-v ${{ github.workspace }}/superset-frontend/coverage:/app/superset-frontend/coverage \
|
||||
--rm $TAG \
|
||||
bash -c \
|
||||
"npm run test -- --coverage --shard=${{ matrix.shard }}/8 --coverageReporters=json"
|
||||
"npm run test -- --coverage --shard=${{ matrix.shard }}/8 --coverageReporters=json-summary"
|
||||
|
||||
- name: Upload Coverage Artifact
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-artifacts-${{ matrix.shard }}
|
||||
path: superset-frontend/coverage
|
||||
@@ -105,41 +99,25 @@ jobs:
|
||||
needs: [sharded-jest-tests]
|
||||
if: needs.frontend-build.outputs.should-run == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 15
|
||||
permissions:
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Download Coverage Artifacts
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
pattern: coverage-artifacts-*
|
||||
path: coverage/
|
||||
|
||||
- name: Reorganize test result reports
|
||||
run: |
|
||||
find coverage/
|
||||
for i in {1..8}; do
|
||||
mv coverage/coverage-artifacts-${i}/coverage-final.json coverage/coverage-shard-${i}.json
|
||||
done
|
||||
shell: bash
|
||||
- name: Show Files
|
||||
run: find coverage/
|
||||
|
||||
- name: Merge Code Coverage
|
||||
run: npx nyc merge coverage/ merged-output/coverage-summary.json
|
||||
|
||||
- name: Upload Code Coverage
|
||||
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
flags: javascript
|
||||
use_oidc: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
verbose: true
|
||||
disable_search: true
|
||||
files: merged-output/coverage-summary.json
|
||||
slug: apache/superset
|
||||
|
||||
@@ -147,63 +125,45 @@ jobs:
|
||||
needs: frontend-build
|
||||
if: needs.frontend-build.outputs.should-run == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Download Docker Image Artifact
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: docker-image
|
||||
|
||||
- name: Load Docker Image
|
||||
run: |
|
||||
zstd -d < docker-image.tar.zst | docker load
|
||||
docker load < docker-image.tar.gz
|
||||
|
||||
- name: lint
|
||||
- name: eslint
|
||||
run: |
|
||||
docker run --rm $TAG bash -c \
|
||||
"npm i && npm run lint"
|
||||
"npm i && npm run eslint -- . --quiet"
|
||||
|
||||
- name: tsc
|
||||
run: |
|
||||
docker run --rm $TAG bash -c \
|
||||
"npm i && npm run plugins:build && npm run type"
|
||||
"npm run type"
|
||||
|
||||
validate-frontend:
|
||||
needs: frontend-build
|
||||
if: needs.frontend-build.outputs.should-run == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Download Docker Image Artifact
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: docker-image
|
||||
|
||||
- name: Load Docker Image
|
||||
run: |
|
||||
zstd -d < docker-image.tar.zst | docker load
|
||||
run: docker load < docker-image.tar.gz
|
||||
|
||||
- name: Build Plugins Packages
|
||||
run: |
|
||||
docker run --rm $TAG bash -c \
|
||||
"npm run plugins:build"
|
||||
|
||||
test-storybook:
|
||||
needs: frontend-build
|
||||
if: needs.frontend-build.outputs.should-run == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 25
|
||||
steps:
|
||||
- name: Download Docker Image Artifact
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
name: docker-image
|
||||
|
||||
- name: Load Docker Image
|
||||
run: |
|
||||
zstd -d < docker-image.tar.zst | docker load
|
||||
|
||||
- name: Build Storybook and Run Tests
|
||||
- name: Build Plugins Storybook
|
||||
run: |
|
||||
docker run --rm $TAG bash -c \
|
||||
"npm run build-storybook && npx playwright install-deps && npx playwright install chromium && npm run test-storybook:ci"
|
||||
"npm run plugins:build-storybook"
|
||||
|
||||
7
.github/workflows/superset-helm-lint.yml
vendored
7
.github/workflows/superset-helm-lint.yml
vendored
@@ -6,9 +6,6 @@ on:
|
||||
paths:
|
||||
- "helm/**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
@@ -19,14 +16,14 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0
|
||||
uses: azure/setup-helm@v4
|
||||
with:
|
||||
version: v3.16.4
|
||||
|
||||
|
||||
14
.github/workflows/superset-helm-release.yml
vendored
14
.github/workflows/superset-helm-release.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ inputs.ref || github.ref_name }}
|
||||
persist-credentials: true
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||
|
||||
- name: Install Helm
|
||||
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0
|
||||
uses: azure/setup-helm@v4
|
||||
with:
|
||||
version: v3.5.4
|
||||
|
||||
@@ -62,8 +62,6 @@ jobs:
|
||||
run: echo "branch_name=helm-publish-${GITHUB_SHA:0:7}" >> $GITHUB_ENV
|
||||
|
||||
- name: Force recreate branch from gh-pages
|
||||
env:
|
||||
BRANCH_NAME: ${{ env.branch_name }}
|
||||
run: |
|
||||
# Ensure a clean working directory
|
||||
git reset --hard
|
||||
@@ -75,13 +73,13 @@ jobs:
|
||||
git fetch origin gh-pages
|
||||
|
||||
# Check out and reset the target branch based on gh-pages
|
||||
git checkout -B "$BRANCH_NAME" origin/gh-pages
|
||||
git checkout -B ${{ env.branch_name }} origin/gh-pages
|
||||
|
||||
# Remove submodules from the branch
|
||||
git submodule deinit -f --all
|
||||
|
||||
# Force push to the remote branch
|
||||
git push origin "$BRANCH_NAME" --force
|
||||
git push origin ${{ env.branch_name }} --force
|
||||
|
||||
# Return to the original branch
|
||||
git checkout local_gha_temp
|
||||
@@ -103,10 +101,10 @@ jobs:
|
||||
CR_RELEASE_NAME_TEMPLATE: "superset-helm-chart-{{ .Version }}"
|
||||
|
||||
- name: Open Pull Request
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const branchName = process.env.BRANCH_NAME;
|
||||
const branchName = '${{ env.branch_name }}';
|
||||
const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/');
|
||||
|
||||
if (!branchName) {
|
||||
|
||||
172
.github/workflows/superset-playwright.yml
vendored
172
.github/workflows/superset-playwright.yml
vendored
@@ -1,172 +0,0 @@
|
||||
name: Playwright Experimental Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "[0-9].[0-9]*"
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ref:
|
||||
description: 'The branch or tag to checkout'
|
||||
required: false
|
||||
default: ''
|
||||
pr_id:
|
||||
description: 'The pull request ID to checkout'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
outputs:
|
||||
python: ${{ steps.check.outputs.python }}
|
||||
frontend: ${{ steps.check.outputs.frontend }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# NOTE: Required Playwright tests are in superset-e2e.yml (E2E / playwright-tests)
|
||||
# This workflow contains only experimental tests that run in shadow mode
|
||||
playwright-tests-experimental:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.frontend == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 30
|
||||
continue-on-error: true
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
browser: ["chromium"]
|
||||
app_root: ["", "/app/prefix"]
|
||||
env:
|
||||
SUPERSET_ENV: development
|
||||
SUPERSET_CONFIG: tests.integration_tests.superset_test_config
|
||||
SUPERSET__SQLALCHEMY_DATABASE_URI: postgresql+psycopg2://superset:superset@127.0.0.1:15432/superset
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
REDIS_PORT: 16379
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
env:
|
||||
POSTGRES_USER: superset
|
||||
POSTGRES_PASSWORD: superset
|
||||
ports:
|
||||
- 15432:5432
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- 16379:6379
|
||||
steps:
|
||||
# -------------------------------------------------------
|
||||
# Conditional checkout based on context (same as Cypress workflow)
|
||||
- name: Checkout for push or pull_request event
|
||||
if: github.event_name == 'push' || github.event_name == 'pull_request'
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
||||
- name: Checkout using ref (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.ref != ''
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ github.event.inputs.ref }}
|
||||
submodules: recursive
|
||||
- name: Checkout using PR ID (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.pr_id != ''
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
|
||||
submodules: recursive
|
||||
# -------------------------------------------------------
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
- name: Setup postgres
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: setup-postgres
|
||||
- name: Import test data
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: playwright_testdata
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
with:
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'superset-frontend/package-lock.json'
|
||||
- name: Install npm dependencies
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: npm-install
|
||||
- name: Build javascript packages
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: build-instrumented-assets
|
||||
- name: Build embedded SDK
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: build-embedded-sdk
|
||||
- name: Install Playwright
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: playwright-install
|
||||
- name: Run Playwright (Experimental Tests)
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
env:
|
||||
NODE_OPTIONS: "--max-old-space-size=4096"
|
||||
with:
|
||||
run: playwright-run "${{ matrix.app_root }}" experimental/
|
||||
- name: Run Playwright (Embedded Tests)
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
env:
|
||||
NODE_OPTIONS: "--max-old-space-size=4096"
|
||||
# Scope embedded-only env vars to this step. Setting them at the job
|
||||
# level enabled the EMBEDDED_SUPERSET feature flag inside Flask for
|
||||
# the preceding "Required Tests" and "Experimental Tests" steps too,
|
||||
# which loads extra handlers and destabilizes the werkzeug dev
|
||||
# server under the 2-worker Playwright load. Required Tests should
|
||||
# match master's Flask configuration.
|
||||
SUPERSET_FEATURE_EMBEDDED_SUPERSET: "true"
|
||||
INCLUDE_EMBEDDED: "true"
|
||||
with:
|
||||
run: playwright-run "${{ matrix.app_root }}" embedded
|
||||
- name: Set safe app root
|
||||
if: failure()
|
||||
id: set-safe-app-root
|
||||
run: |
|
||||
APP_ROOT="${{ matrix.app_root }}"
|
||||
SAFE_APP_ROOT=${APP_ROOT//\//_}
|
||||
echo "safe_app_root=$SAFE_APP_ROOT" >> $GITHUB_OUTPUT
|
||||
- name: Upload Playwright Artifacts
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
if: failure()
|
||||
with:
|
||||
path: |
|
||||
${{ github.workspace }}/superset-frontend/playwright-results/
|
||||
${{ github.workspace }}/superset-frontend/test-results/
|
||||
name: playwright-experimental-artifact-${{ github.run_id }}-${{ github.job }}-${{ matrix.browser }}--${{ steps.set-safe-app-root.outputs.safe_app_root }}
|
||||
@@ -14,32 +14,8 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
outputs:
|
||||
python: ${{ steps.check.outputs.python }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
test-mysql:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
id-token: write
|
||||
env:
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
SUPERSET_CONFIG: tests.integration_tests.superset_test_config
|
||||
@@ -49,8 +25,6 @@ jobs:
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
# Authenticated pulls use our higher Docker Hub rate limit. Empty on
|
||||
# fork PRs (secrets unavailable) -> runner falls back to anonymous.
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
ports:
|
||||
@@ -67,70 +41,43 @@ jobs:
|
||||
- 16379:6379
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
if: steps.check.outputs.python
|
||||
- name: Setup MySQL
|
||||
if: steps.check.outputs.python
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: setup-mysql
|
||||
- name: Start Celery worker
|
||||
if: steps.check.outputs.python
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: celery-worker
|
||||
- name: Python integration tests (MySQL)
|
||||
if: steps.check.outputs.python
|
||||
run: |
|
||||
./scripts/python_tests.sh
|
||||
- name: Upload code coverage
|
||||
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
flags: python,mysql
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
verbose: true
|
||||
use_oidc: true
|
||||
slug: apache/superset
|
||||
- name: Generate database diagnostics for docs
|
||||
env:
|
||||
SUPERSET_CONFIG: tests.integration_tests.superset_test_config
|
||||
SUPERSET__SQLALCHEMY_DATABASE_URI: |
|
||||
mysql+mysqldb://superset:superset@127.0.0.1:13306/superset?charset=utf8mb4&binary_prefix=true
|
||||
run: |
|
||||
python -c "
|
||||
import json
|
||||
from superset.app import create_app
|
||||
from superset.db_engine_specs.lib import generate_yaml_docs
|
||||
app = create_app()
|
||||
with app.app_context():
|
||||
docs = generate_yaml_docs()
|
||||
# Wrap in the expected format
|
||||
output = {
|
||||
'generated': '$(date -Iseconds)',
|
||||
'databases': docs
|
||||
}
|
||||
with open('databases-diagnostics.json', 'w') as f:
|
||||
json.dump(output, f, indent=2, default=str)
|
||||
print(f'Generated diagnostics for {len(docs)} databases')
|
||||
"
|
||||
- name: Upload database diagnostics artifact
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
name: database-diagnostics
|
||||
path: databases-diagnostics.json
|
||||
retention-days: 7
|
||||
test-postgres:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
id-token: write
|
||||
strategy:
|
||||
matrix:
|
||||
# Full version spread on push (master/release) + nightly; current only
|
||||
# on PRs to cut runner cost (cross-version breaks are caught at merge).
|
||||
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["current", "previous", "next"]') }}
|
||||
python-version: ["current", "previous", "next"]
|
||||
env:
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
SUPERSET_CONFIG: tests.integration_tests.superset_test_config
|
||||
@@ -138,7 +85,7 @@ jobs:
|
||||
SUPERSET__SQLALCHEMY_DATABASE_URI: postgresql+psycopg2://superset:superset@127.0.0.1:15432/superset
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
POSTGRES_USER: superset
|
||||
POSTGRES_PASSWORD: superset
|
||||
@@ -152,41 +99,44 @@ jobs:
|
||||
- 16379:6379
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
if: steps.check.outputs.python
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Setup Postgres
|
||||
if: steps.check.outputs.python
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: |
|
||||
setup-postgres
|
||||
- name: Start Celery worker
|
||||
if: steps.check.outputs.python
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: celery-worker
|
||||
- name: Python integration tests (PostgreSQL)
|
||||
if: steps.check.outputs.python
|
||||
run: |
|
||||
./scripts/python_tests.sh
|
||||
- name: Upload code coverage
|
||||
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
flags: python,postgres
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
verbose: true
|
||||
use_oidc: true
|
||||
slug: apache/superset
|
||||
|
||||
test-sqlite:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
id-token: write
|
||||
env:
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
SUPERSET_CONFIG: tests.integration_tests.superset_test_config
|
||||
@@ -202,51 +152,37 @@ jobs:
|
||||
- 16379:6379
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
if: steps.check.outputs.python
|
||||
- name: Install dependencies
|
||||
if: steps.check.outputs.python
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: |
|
||||
# sqlite needs this working directory
|
||||
mkdir ${{ github.workspace }}/.temp
|
||||
- name: Start Celery worker
|
||||
if: steps.check.outputs.python
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: celery-worker
|
||||
- name: Python integration tests (SQLite)
|
||||
if: steps.check.outputs.python
|
||||
run: |
|
||||
./scripts/python_tests.sh
|
||||
- name: Upload code coverage
|
||||
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
flags: python,sqlite
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
verbose: true
|
||||
use_oidc: true
|
||||
slug: apache/superset
|
||||
|
||||
# Stable required-status-check anchor for the matrix-based test-postgres job.
|
||||
# It is gated on change detection, so on non-Python PRs it is skipped and
|
||||
# never produces its `test-postgres (current)` context (a job-level skip
|
||||
# happens before matrix expansion). This always-running job reports a single
|
||||
# context branch protection can require: it passes when test-postgres
|
||||
# succeeded or was skipped, and fails only on a real failure.
|
||||
test-postgres-required:
|
||||
needs: [changes, test-postgres]
|
||||
if: always()
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Check test-postgres result
|
||||
env:
|
||||
RESULT: ${{ needs.test-postgres.result }}
|
||||
run: |
|
||||
if [ "$RESULT" != "success" ] && [ "$RESULT" != "skipped" ]; then
|
||||
echo "test-postgres did not pass (result: $RESULT)"
|
||||
exit 1
|
||||
fi
|
||||
echo "test-postgres result: $RESULT"
|
||||
|
||||
@@ -15,32 +15,8 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
outputs:
|
||||
python: ${{ steps.check.outputs.python }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
test-postgres-presto:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
id-token: write
|
||||
env:
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
SUPERSET_CONFIG: tests.integration_tests.superset_test_config
|
||||
@@ -49,7 +25,7 @@ jobs:
|
||||
SUPERSET__SQLALCHEMY_EXAMPLES_URI: presto://localhost:15433/memory/default
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
POSTGRES_USER: superset
|
||||
POSTGRES_PASSWORD: superset
|
||||
@@ -72,38 +48,43 @@ jobs:
|
||||
- 16379:6379
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
if: steps.check.outputs.python == 'true'
|
||||
- name: Setup Postgres
|
||||
if: steps.check.outputs.python
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: setup-postgres
|
||||
run: |
|
||||
echo "${{ steps.check.outputs.python }}"
|
||||
setup-postgres
|
||||
- name: Start Celery worker
|
||||
if: steps.check.outputs.python
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: celery-worker
|
||||
- name: Python unit tests (PostgreSQL)
|
||||
if: steps.check.outputs.python
|
||||
run: |
|
||||
./scripts/python_tests.sh -m 'chart_data_flow or sql_json_flow'
|
||||
- name: Upload code coverage
|
||||
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
flags: python,presto
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
verbose: true
|
||||
use_oidc: true
|
||||
slug: apache/superset
|
||||
|
||||
test-postgres-hive:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
id-token: write
|
||||
env:
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
SUPERSET_CONFIG: tests.integration_tests.superset_test_config
|
||||
@@ -113,7 +94,7 @@ jobs:
|
||||
UPLOAD_FOLDER: /tmp/.superset/uploads/
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
POSTGRES_USER: superset
|
||||
POSTGRES_PASSWORD: superset
|
||||
@@ -127,34 +108,45 @@ jobs:
|
||||
- 16379:6379
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Create csv upload directory
|
||||
if: steps.check.outputs.python
|
||||
run: sudo mkdir -p /tmp/.superset/uploads
|
||||
- name: Give write access to the csv upload directory
|
||||
if: steps.check.outputs.python
|
||||
run: sudo chown -R $USER:$USER /tmp/.superset
|
||||
- name: Start hadoop and hive
|
||||
if: steps.check.outputs.python
|
||||
run: docker compose -f scripts/databases/hive/docker-compose.yml up -d
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
if: steps.check.outputs.python
|
||||
- name: Setup Postgres
|
||||
if: steps.check.outputs.python
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: setup-postgres
|
||||
- name: Start Celery worker
|
||||
if: steps.check.outputs.python
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
with:
|
||||
run: celery-worker
|
||||
- name: Python unit tests (PostgreSQL)
|
||||
if: steps.check.outputs.python
|
||||
run: |
|
||||
pip install -e .[hive]
|
||||
./scripts/python_tests.sh -m 'chart_data_flow or sql_json_flow'
|
||||
- name: Upload code coverage
|
||||
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
flags: python,hive
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
verbose: true
|
||||
use_oidc: true
|
||||
slug: apache/superset
|
||||
|
||||
70
.github/workflows/superset-python-unittest.yml
vendored
70
.github/workflows/superset-python-unittest.yml
vendored
@@ -15,88 +15,46 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
unit-tests:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
outputs:
|
||||
python: ${{ steps.check.outputs.python }}
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["previous", "current", "next"]
|
||||
env:
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
unit-tests:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
id-token: write
|
||||
strategy:
|
||||
matrix:
|
||||
# Full version spread on push (master/release) + nightly; current only
|
||||
# on PRs to cut runner cost (cross-version breaks are caught at merge).
|
||||
python-version: ${{ github.event_name == 'pull_request' && fromJSON('["current"]') || fromJSON('["previous", "current", "next"]') }}
|
||||
env:
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
- name: Setup Python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
if: steps.check.outputs.python
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Python unit tests
|
||||
if: steps.check.outputs.python
|
||||
env:
|
||||
SUPERSET_TESTENV: true
|
||||
SUPERSET_SECRET_KEY: not-a-secret
|
||||
run: |
|
||||
pytest --durations-min=0.5 --cov-report= --cov=superset ./tests/common ./tests/unit_tests --cache-clear --maxfail=50
|
||||
- name: Python 100% coverage unit tests
|
||||
if: steps.check.outputs.python
|
||||
env:
|
||||
SUPERSET_TESTENV: true
|
||||
SUPERSET_SECRET_KEY: not-a-secret
|
||||
run: |
|
||||
pytest --durations-min=0.5 --cov=superset/sql/ ./tests/unit_tests/sql/ --cache-clear --cov-fail-under=100
|
||||
pytest --durations-min=0.5 --cov=superset/semantic_layers/ ./tests/unit_tests/semantic_layers/ --cache-clear --cov-fail-under=100
|
||||
- name: Upload code coverage
|
||||
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
flags: python,unit
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
verbose: true
|
||||
use_oidc: true
|
||||
slug: apache/superset
|
||||
|
||||
# Stable required-status-check anchor. `unit-tests` is a matrix job gated on
|
||||
# change detection, so on non-Python PRs it is skipped and never produces its
|
||||
# `unit-tests (current)` context (a job-level skip happens before matrix
|
||||
# expansion). This always-running job reports a single context that branch
|
||||
# protection can require: it passes when unit-tests succeeded or was skipped,
|
||||
# and fails only on a real failure.
|
||||
unit-tests-required:
|
||||
needs: [changes, unit-tests]
|
||||
if: always()
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Check unit-tests result
|
||||
env:
|
||||
RESULT: ${{ needs.unit-tests.result }}
|
||||
run: |
|
||||
if [ "$RESULT" != "success" ] && [ "$RESULT" != "skipped" ]; then
|
||||
echo "unit-tests did not pass (result: $RESULT)"
|
||||
exit 1
|
||||
fi
|
||||
echo "unit-tests result: $RESULT"
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
name: Translation Regression Comment
|
||||
|
||||
on:
|
||||
# zizmor: ignore[dangerous-triggers] - runs in base-branch context and only consumes the uploaded artifact; never checks out PR code (see note below)
|
||||
workflow_run:
|
||||
workflows: ["Translations"]
|
||||
types: [completed]
|
||||
|
||||
# This workflow posts a PR comment when the Translations workflow detects a
|
||||
# regression. It uses the workflow_run trigger so that it always runs in the
|
||||
# base-branch context and can safely be granted write permissions, even for
|
||||
# PRs from forks.
|
||||
#
|
||||
# IMPORTANT: This workflow must NEVER check out code from the PR branch.
|
||||
# All data comes from the artifact uploaded by the Translations workflow.
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
actions: read
|
||||
|
||||
jobs:
|
||||
post-comment:
|
||||
runs-on: ubuntu-24.04
|
||||
# Only act when the Translations workflow failed (which means a regression
|
||||
# was detected — the workflow exits 1 on regression).
|
||||
if: github.event.workflow_run.conclusion == 'failure'
|
||||
|
||||
steps:
|
||||
- name: Download regression artifact
|
||||
id: download
|
||||
continue-on-error: true
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
name: translation-regression
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path: /tmp/translation-regression
|
||||
|
||||
- name: Post or update PR comment
|
||||
if: steps.download.outcome == 'success'
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
|
||||
const prNumberFile = '/tmp/translation-regression/pr-number.txt';
|
||||
const reportFile = '/tmp/translation-regression/regression-report.md';
|
||||
|
||||
if (!fs.existsSync(prNumberFile) || !fs.existsSync(reportFile)) {
|
||||
console.log('Artifact files not found, skipping comment.');
|
||||
return;
|
||||
}
|
||||
|
||||
const prNumber = parseInt(fs.readFileSync(prNumberFile, 'utf8').trim(), 10);
|
||||
if (!prNumber) {
|
||||
console.log('Could not parse PR number, skipping comment.');
|
||||
return;
|
||||
}
|
||||
|
||||
const report = fs.readFileSync(reportFile, 'utf8');
|
||||
const marker = '<!-- translation-regression-bot -->';
|
||||
const body = `${marker}\n${report}`;
|
||||
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: prNumber,
|
||||
});
|
||||
|
||||
const existing = comments.find(c => c.body && c.body.includes(marker));
|
||||
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: existing.id,
|
||||
body,
|
||||
});
|
||||
console.log(`Updated existing comment ${existing.id} on PR #${prNumber}`);
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: prNumber,
|
||||
body,
|
||||
});
|
||||
console.log(`Created new comment on PR #${prNumber}`);
|
||||
}
|
||||
100
.github/workflows/superset-translations.yml
vendored
100
.github/workflows/superset-translations.yml
vendored
@@ -8,10 +8,6 @@ on:
|
||||
pull_request:
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
@@ -20,12 +16,9 @@ concurrency:
|
||||
jobs:
|
||||
frontend-check-translations:
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
@@ -38,11 +31,9 @@ jobs:
|
||||
|
||||
- name: Setup Node.js
|
||||
if: steps.check.outputs.frontend
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'superset-frontend/package-lock.json'
|
||||
- name: Install dependencies
|
||||
if: steps.check.outputs.frontend
|
||||
uses: ./.github/actions/cached-dependencies
|
||||
@@ -56,16 +47,12 @@ jobs:
|
||||
|
||||
babel-extract:
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
submodules: recursive
|
||||
|
||||
- name: Check for file changes
|
||||
id: check
|
||||
uses: ./.github/actions/change-detector/
|
||||
@@ -73,83 +60,8 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Setup Python
|
||||
if: steps.check.outputs.python == 'true' || steps.check.outputs.frontend == 'true'
|
||||
if: steps.check.outputs.python
|
||||
uses: ./.github/actions/setup-backend/
|
||||
|
||||
- name: Install gettext tools
|
||||
if: steps.check.outputs.python == 'true' || steps.check.outputs.frontend == 'true'
|
||||
run: sudo apt-get update && sudo apt-get install -y gettext
|
||||
|
||||
# Fetch the base ref so we can compare PR-introduced regressions
|
||||
# against a fair baseline (also runs babel_update against the base
|
||||
# source) — this isolates the PR's contribution from any pre-existing
|
||||
# drift on the base branch.
|
||||
- name: Fetch base ref and create comparison worktree
|
||||
if: steps.check.outputs.python == 'true' || steps.check.outputs.frontend == 'true'
|
||||
env:
|
||||
PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
|
||||
run: |
|
||||
# For PRs use the base branch; for direct pushes compare against the previous commit.
|
||||
BASE_REF="$PR_BASE_REF"
|
||||
if [ -n "$BASE_REF" ]; then
|
||||
git fetch --depth=1 origin "$BASE_REF"
|
||||
else
|
||||
git fetch --depth=2 origin "$GITHUB_REF"
|
||||
fi
|
||||
git worktree add /tmp/base-worktree FETCH_HEAD
|
||||
|
||||
# Run babel_update against BASE source + BASE translations. Any drift
|
||||
# already present on the base branch (source strings that have changed
|
||||
# without .po updates) shows up here as fuzzies — and will also show
|
||||
# up in the PR run, so it cancels out in the comparison.
|
||||
- name: Baseline — run babel_update against BASE source
|
||||
if: steps.check.outputs.python == 'true' || steps.check.outputs.frontend == 'true'
|
||||
working-directory: /tmp/base-worktree
|
||||
- name: Test babel extraction
|
||||
if: steps.check.outputs.python
|
||||
run: ./scripts/translations/babel_update.sh
|
||||
|
||||
- name: Record baseline translation counts
|
||||
if: steps.check.outputs.python == 'true' || steps.check.outputs.frontend == 'true'
|
||||
run: |
|
||||
python scripts/translations/check_translation_regression.py \
|
||||
--count \
|
||||
--translations-dir /tmp/base-worktree/superset/translations \
|
||||
> /tmp/before.json
|
||||
|
||||
# Run babel_update against the PR source and PR translations. This keeps
|
||||
# committed .po fixes in play while the base babel_update above still
|
||||
# cancels out translation drift already present on the base branch.
|
||||
- name: Run babel_update against PR source
|
||||
if: steps.check.outputs.python == 'true' || steps.check.outputs.frontend == 'true'
|
||||
run: ./scripts/translations/babel_update.sh
|
||||
|
||||
- name: Check for translation regression
|
||||
id: regression
|
||||
if: steps.check.outputs.python == 'true' || steps.check.outputs.frontend == 'true'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
python scripts/translations/check_translation_regression.py \
|
||||
--compare /tmp/before.json \
|
||||
--report /tmp/regression-report.md
|
||||
|
||||
# Save the PR number so the comment workflow can post the report without
|
||||
# needing write permissions on this pull_request-triggered job.
|
||||
- name: Save PR number for comment workflow
|
||||
if: >-
|
||||
github.event_name == 'pull_request' &&
|
||||
steps.regression.outcome == 'failure'
|
||||
run: echo "${{ github.event.pull_request.number }}" > /tmp/pr-number.txt
|
||||
|
||||
- name: Upload regression artifact
|
||||
if: >-
|
||||
github.event_name == 'pull_request' &&
|
||||
steps.regression.outcome == 'failure'
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
name: translation-regression
|
||||
path: |
|
||||
/tmp/regression-report.md
|
||||
/tmp/pr-number.txt
|
||||
|
||||
- name: Fail if regression detected
|
||||
if: steps.regression.outcome == 'failure'
|
||||
run: exit 1
|
||||
|
||||
6
.github/workflows/superset-websocket.yml
vendored
6
.github/workflows/superset-websocket.yml
vendored
@@ -11,9 +11,6 @@ on:
|
||||
- "superset-websocket/**"
|
||||
types: [synchronize, opened, reopened, ready_for_review]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# cancel previous workflow jobs for PRs
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
|
||||
@@ -22,10 +19,9 @@ concurrency:
|
||||
jobs:
|
||||
app-checks:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install dependencies
|
||||
|
||||
4
.github/workflows/supersetbot.yml
vendored
4
.github/workflows/supersetbot.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
steps:
|
||||
- name: Quickly add thumbs up!
|
||||
if: github.event_name == 'issue_comment' && contains(github.event.comment.body, '@supersetbot')
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/')
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
});
|
||||
|
||||
- name: "Checkout ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
41
.github/workflows/tag-release.yml
vendored
41
.github/workflows/tag-release.yml
vendored
@@ -21,9 +21,6 @@ on:
|
||||
options:
|
||||
- 'true'
|
||||
- 'false'
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -34,19 +31,15 @@ jobs:
|
||||
id: check
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${DOCKERHUB_USER}" ]; then
|
||||
if [ -n "${{ (secrets.DOCKERHUB_USER != '' && secrets.DOCKERHUB_TOKEN != '') || '' }}" ]; then
|
||||
echo "has-secrets=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
env:
|
||||
DOCKERHUB_USER: ${{ (secrets.DOCKERHUB_USER != '' && secrets.DOCKERHUB_TOKEN != '') || '' }}
|
||||
docker-release:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
name: docker-release
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
build_preset: ["dev", "lean", "py310", "websocket", "dockerize", "py311", "py312"]
|
||||
@@ -54,9 +47,8 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Docker Environment
|
||||
@@ -68,11 +60,9 @@ jobs:
|
||||
build: "true"
|
||||
|
||||
- name: Use Node.js 20
|
||||
# zizmor: ignore[cache-poisoning] - node only runs the supersetbot CLI; no dependency cache is enabled
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Setup supersetbot
|
||||
uses: ./.github/actions/setup-supersetbot/
|
||||
@@ -82,21 +72,17 @@ jobs:
|
||||
DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
|
||||
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
INPUT_RELEASE: ${{ github.event.inputs.release }}
|
||||
INPUT_FORCE_LATEST: ${{ github.event.inputs.force-latest }}
|
||||
INPUT_GIT_REF: ${{ github.event.inputs.git-ref }}
|
||||
GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
RELEASE="${GITHUB_EVENT_RELEASE_TAG_NAME}"
|
||||
RELEASE="${{ github.event.release.tag_name }}"
|
||||
FORCE_LATEST=""
|
||||
EVENT="${{github.event_name}}"
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
# in the case of a manually-triggered run, read release from input
|
||||
RELEASE="${INPUT_RELEASE}"
|
||||
if [ "${INPUT_FORCE_LATEST}" = "true" ]; then
|
||||
RELEASE="${{ github.event.inputs.release }}"
|
||||
if [ "${{ github.event.inputs.force-latest }}" = "true" ]; then
|
||||
FORCE_LATEST="--force-latest"
|
||||
fi
|
||||
git checkout "${INPUT_GIT_REF}"
|
||||
git checkout "${{ github.event.inputs.git-ref }}"
|
||||
EVENT="release"
|
||||
fi
|
||||
|
||||
@@ -121,17 +107,14 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node.js 20
|
||||
# zizmor: ignore[cache-poisoning] - node only runs the supersetbot CLI; no dependency cache is enabled
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Setup supersetbot
|
||||
uses: ./.github/actions/setup-supersetbot/
|
||||
@@ -139,15 +122,13 @@ jobs:
|
||||
- name: Label the PRs with the right release-related labels
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
INPUT_RELEASE: ${{ github.event.inputs.release }}
|
||||
GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
export GITHUB_ACTOR=""
|
||||
git fetch --all --tags
|
||||
git checkout master
|
||||
RELEASE="${GITHUB_EVENT_RELEASE_TAG_NAME}"
|
||||
RELEASE="${{ github.event.release.tag_name }}"
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
# in the case of a manually-triggered run, read release from input
|
||||
RELEASE="${INPUT_RELEASE}"
|
||||
RELEASE="${{ github.event.inputs.release }}"
|
||||
fi
|
||||
supersetbot release-label $RELEASE
|
||||
|
||||
13
.github/workflows/tech-debt.yml
vendored
13
.github/workflows/tech-debt.yml
vendored
@@ -6,9 +6,6 @@ on:
|
||||
- master
|
||||
- "[0-9].[0-9]*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
config:
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -19,12 +16,10 @@ jobs:
|
||||
id: check
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${GSHEET_KEY}" ]; then
|
||||
if [ -n "${{ (secrets.GSHEET_KEY != '' ) || '' }}" ]; then
|
||||
echo "has-secrets=1" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
env:
|
||||
GSHEET_KEY: ${{ (secrets.GSHEET_KEY != '' ) || '' }}
|
||||
process-and-upload:
|
||||
needs: config
|
||||
if: needs.config.outputs.has-secrets
|
||||
@@ -32,12 +27,10 @@ jobs:
|
||||
name: Generate Reports
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: './superset-frontend/.nvmrc'
|
||||
|
||||
|
||||
15
.github/workflows/welcome-new-users.yml
vendored
15
.github/workflows/welcome-new-users.yml
vendored
@@ -1,29 +1,22 @@
|
||||
name: Welcome New Contributor
|
||||
|
||||
on:
|
||||
# zizmor: ignore[dangerous-triggers] - posts a welcome comment only; does not check out or execute PR-provided code
|
||||
pull_request_target:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
welcome:
|
||||
runs-on: ubuntu-24.04
|
||||
if: github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- name: Welcome Message
|
||||
uses: actions/first-interaction@1c4688942c71f71d4f5502a26ea67c331730fa4d # v3.1.0
|
||||
uses: actions/first-interaction@v3
|
||||
continue-on-error: true
|
||||
with:
|
||||
repo_token: ${{ github.token }}
|
||||
issue_message: |-
|
||||
Congrats on opening your first issue and thank you for contributing to Superset! :tada: :heart:
|
||||
|
||||
Please read our [New Contributor Welcome & Expectations](https://github.com/apache/superset/wiki/New-Contributor-Welcome-&-Expectations) guide.
|
||||
pr_message: |-
|
||||
repo-token: ${{ github.token }}
|
||||
pr-message: |-
|
||||
Congrats on making your first PR and thank you for contributing to Superset! :tada: :heart:
|
||||
|
||||
Please read our [New Contributor Welcome & Expectations](https://github.com/apache/superset/wiki/New-Contributor-Welcome-&-Expectations) guide.
|
||||
|
||||
We hope to see you in our [Slack](https://apache-superset.slack.com/) community too! Not signed up? Use our [Slack App](http://bit.ly/join-superset-slack) to self-register.
|
||||
|
||||
17
.gitignore
vendored
17
.gitignore
vendored
@@ -33,7 +33,6 @@ cover
|
||||
.env
|
||||
.envrc
|
||||
.idea
|
||||
.roo
|
||||
.mypy_cache
|
||||
.python-version
|
||||
.tox
|
||||
@@ -61,19 +60,21 @@ tmp
|
||||
rat-results.txt
|
||||
superset/app/
|
||||
superset-websocket/config.json
|
||||
.direnv
|
||||
*.log
|
||||
|
||||
# Node.js, webpack artifacts, storybook
|
||||
*.entry.js
|
||||
*.js.map
|
||||
node_modules
|
||||
npm-debug.log*
|
||||
superset/static/*
|
||||
superset/static/assets/*
|
||||
!superset/static/assets/.gitkeep
|
||||
superset/static/uploads/*
|
||||
!superset/static/uploads/.gitkeep
|
||||
superset/static/version_info.json
|
||||
superset-frontend/**/esm/*
|
||||
superset-frontend/**/lib/*
|
||||
superset-frontend/**/storybook-static/*
|
||||
superset-frontend/migration-storybook.log
|
||||
yarn-error.log
|
||||
*.map
|
||||
*.min.js
|
||||
@@ -115,15 +116,11 @@ release.json
|
||||
superset/translations/**/messages.json
|
||||
# these mo binary files are generated by `pybabel compile`
|
||||
superset/translations/**/messages.mo
|
||||
# cross-language index generated by scripts/translations/build_translation_index.py
|
||||
superset/translations/translation_index.json
|
||||
|
||||
docker/requirements-local.txt
|
||||
|
||||
cache/
|
||||
docker/*local*
|
||||
docker/superset-websocket/config.json
|
||||
docker-compose.override.yml
|
||||
|
||||
.temp_cache
|
||||
|
||||
@@ -136,8 +133,4 @@ CLAUDE.local.md
|
||||
PROJECT.md
|
||||
.aider*
|
||||
.claude_rc*
|
||||
.claude/settings.local.json
|
||||
.env.local
|
||||
oxc-custom-build/
|
||||
*.code-workspace
|
||||
*.duckdb
|
||||
|
||||
@@ -27,7 +27,6 @@ repos:
|
||||
args: [--check-untyped-defs]
|
||||
exclude: ^superset-extensions-cli/
|
||||
additional_dependencies: [
|
||||
types-cachetools,
|
||||
types-simplejson,
|
||||
types-python-dateutil,
|
||||
types-requests,
|
||||
@@ -50,40 +49,26 @@ repos:
|
||||
hooks:
|
||||
- id: check-docstring-first
|
||||
- id: check-added-large-files
|
||||
exclude: ^.*\.(geojson)$|^docs/static/img/screenshots/.*|^superset-frontend/CHANGELOG\.md$|^superset/examples/.*/data\.parquet$|^superset/translations/.*\.po$
|
||||
exclude: ^.*\.(geojson)$|^docs/static/img/screenshots/.*|^superset-frontend/CHANGELOG\.md$
|
||||
- id: check-yaml
|
||||
exclude: ^helm/superset/templates/
|
||||
- id: debug-statements
|
||||
- id: end-of-file-fixer
|
||||
exclude: .*/lerna\.json$|^docs/static/img/logos/
|
||||
exclude: .*/lerna\.json$
|
||||
- id: trailing-whitespace
|
||||
exclude: ^.*\.(snap)
|
||||
args: ["--markdown-linebreak-ext=md"]
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: prettier-frontend
|
||||
name: prettier (frontend)
|
||||
entry: bash -c 'cd superset-frontend && for file in "$@"; do npx prettier --write "${file#superset-frontend/}"; done'
|
||||
language: system
|
||||
pass_filenames: true
|
||||
files: ^superset-frontend/.*\.(js|jsx|ts|tsx|css|scss|sass|json)$
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: oxlint-frontend
|
||||
name: oxlint (frontend)
|
||||
entry: ./scripts/oxlint.sh
|
||||
language: system
|
||||
pass_filenames: true
|
||||
files: ^superset-frontend/.*\.(js|jsx|ts|tsx)$
|
||||
- id: custom-rules-frontend
|
||||
name: custom rules (frontend)
|
||||
entry: ./scripts/check-custom-rules.sh
|
||||
- id: eslint-frontend
|
||||
name: eslint (frontend)
|
||||
entry: ./scripts/eslint.sh
|
||||
language: system
|
||||
pass_filenames: true
|
||||
files: ^superset-frontend/.*\.(js|jsx|ts|tsx)$
|
||||
- id: eslint-docs
|
||||
name: eslint (docs)
|
||||
entry: bash -c 'cd docs && FILES=$(printf "%s\n" "$@" | sed "s|^docs/||" | tr "\n" " ") && yarn eslint --fix --quiet $FILES'
|
||||
entry: bash -c 'cd docs && FILES=$(echo "$@" | sed "s|docs/||g") && yarn eslint --fix --ext .js,.jsx,.ts,.tsx --quiet $FILES'
|
||||
language: system
|
||||
pass_filenames: true
|
||||
files: ^docs/.*\.(js|jsx|ts|tsx)$
|
||||
@@ -107,19 +92,12 @@ repos:
|
||||
files: helm
|
||||
verbose: false
|
||||
args: ["--log-level", "error"]
|
||||
# Using local hooks ensures ruff version matches requirements/development.txt
|
||||
- repo: local
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.9.7
|
||||
hooks:
|
||||
- id: ruff-format
|
||||
name: ruff-format
|
||||
entry: ruff format
|
||||
language: system
|
||||
types: [python]
|
||||
- id: ruff
|
||||
name: ruff
|
||||
entry: ruff check --fix --show-fixes
|
||||
language: system
|
||||
types: [python]
|
||||
args: [--fix]
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: pylint
|
||||
@@ -132,40 +110,11 @@ repos:
|
||||
- -c
|
||||
- |
|
||||
TARGET_BRANCH=${GITHUB_BASE_REF:-master}
|
||||
# Only fetch if we're not in CI (CI already has all refs)
|
||||
if [ -z "$CI" ]; then
|
||||
git fetch --no-recurse-submodules origin "$TARGET_BRANCH" 2>/dev/null || true
|
||||
fi
|
||||
BASE=$(git merge-base origin/"$TARGET_BRANCH" HEAD 2>/dev/null) || BASE="HEAD"
|
||||
files=$(git diff --name-only --diff-filter=ACM "$BASE"..HEAD 2>/dev/null | grep '^superset/.*\.py$' || true)
|
||||
git fetch origin "$TARGET_BRANCH"
|
||||
BASE=$(git merge-base origin/"$TARGET_BRANCH" HEAD)
|
||||
files=$(git diff --name-only --diff-filter=ACM "$BASE"..HEAD | grep '^superset/.*\.py$' || true)
|
||||
if [ -n "$files" ]; then
|
||||
pylint --rcfile=.pylintrc --load-plugins=superset.extensions.pylint --reports=no $files
|
||||
else
|
||||
echo "No Python files to lint."
|
||||
fi
|
||||
- id: db-engine-spec-metadata
|
||||
name: database engine spec metadata validation
|
||||
entry: python superset/db_engine_specs/lint_metadata.py --strict
|
||||
language: system
|
||||
files: ^superset/db_engine_specs/.*\.py$
|
||||
exclude: ^superset/db_engine_specs/(base|lib|lint_metadata|__init__)\.py$
|
||||
pass_filenames: false
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: feature-flags-sync
|
||||
name: feature flags documentation sync
|
||||
entry: bash -c 'python scripts/extract_feature_flags.py > docs/static/feature-flags.json.tmp && if ! diff -q docs/static/feature-flags.json docs/static/feature-flags.json.tmp > /dev/null 2>&1; then mv docs/static/feature-flags.json.tmp docs/static/feature-flags.json && echo "Updated docs/static/feature-flags.json" && exit 1; else rm docs/static/feature-flags.json.tmp; fi'
|
||||
language: system
|
||||
files: ^superset/config\.py$
|
||||
pass_filenames: false
|
||||
- id: zizmor
|
||||
name: zizmor (GHA security audit)
|
||||
entry: zizmor
|
||||
language: python
|
||||
additional_dependencies: [zizmor==1.25.2]
|
||||
files: ^\.github/
|
||||
types: [yaml]
|
||||
pass_filenames: false
|
||||
# Advisory until pre-existing findings are resolved; remove
|
||||
# --no-exit-codes to make this hook blocking.
|
||||
args: [--no-exit-codes, .github/]
|
||||
|
||||
@@ -53,7 +53,7 @@ extension-pkg-whitelist=pyarrow
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
disable=all
|
||||
enable=disallowed-sql-import,consider-using-transaction
|
||||
enable=disallowed-json-import,disallowed-sql-import,consider-using-transaction
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
.nvmrc
|
||||
.prettierrc
|
||||
.rat-excludes
|
||||
.swcrc
|
||||
.*log
|
||||
.*pyc
|
||||
.*lock
|
||||
@@ -43,9 +42,6 @@ _build/*
|
||||
_static/*
|
||||
.buildinfo
|
||||
searchindex.js
|
||||
# auto-generated by docs/scripts/convert-api-sidebar.mjs from openapi.json
|
||||
sidebar.js
|
||||
sidebar.ts
|
||||
# auto generated
|
||||
requirements/*
|
||||
# vendorized
|
||||
@@ -70,20 +66,22 @@ temporary_superset_ui/*
|
||||
# skip license checks for auto-generated test snapshots
|
||||
.*snap
|
||||
|
||||
# docs third-party logos (database logos, org logos, etc.)
|
||||
databases/*
|
||||
logos/*
|
||||
# docs overrides for third party logos we don't have the rights to
|
||||
google-big-query.svg
|
||||
google-sheets.svg
|
||||
ibm-db2.svg
|
||||
postgresql.svg
|
||||
snowflake.svg
|
||||
ydb.svg
|
||||
loading.svg
|
||||
|
||||
# docs-related
|
||||
erd.puml
|
||||
erd.svg
|
||||
intro_header.txt
|
||||
TODO.md
|
||||
|
||||
# for LLMs
|
||||
llm-context.md
|
||||
llms.txt
|
||||
AGENTS.md
|
||||
LLMS.md
|
||||
CLAUDE.md
|
||||
CURSOR.md
|
||||
|
||||
307
AGENTS.md
307
AGENTS.md
@@ -1,307 +0,0 @@
|
||||
# LLM Context Guide for Apache Superset
|
||||
|
||||
Apache Superset is a data visualization platform with Flask/Python backend and React/TypeScript frontend.
|
||||
|
||||
## ⚠️ CRITICAL: Always Run Pre-commit Before Pushing
|
||||
|
||||
**ALWAYS run `pre-commit run --all-files` before pushing commits.** CI will fail if pre-commit checks don't pass. This is non-negotiable.
|
||||
|
||||
```bash
|
||||
# Stage your changes first
|
||||
git add .
|
||||
|
||||
# Run pre-commit on all files
|
||||
pre-commit run --all-files
|
||||
|
||||
# If there are auto-fixes, stage them and commit
|
||||
git add .
|
||||
git commit --amend # or new commit
|
||||
```
|
||||
|
||||
Common pre-commit failures:
|
||||
- **Formatting** - black, prettier, eslint will auto-fix
|
||||
- **Type errors** - mypy failures need manual fixes
|
||||
- **Linting** - ruff, pylint issues need manual fixes
|
||||
|
||||
## ⚠️ CRITICAL: Ongoing Refactors (What NOT to Do)
|
||||
|
||||
**These migrations are actively happening - avoid deprecated patterns:**
|
||||
|
||||
### Frontend Modernization
|
||||
- **NO `any` types** - Use proper TypeScript types
|
||||
- **NO JavaScript files** - Convert to TypeScript (.ts/.tsx)
|
||||
- **Use @superset-ui/core** - Don't import Ant Design directly, prefer Ant Design component wrappers from @superset-ui/core/components
|
||||
- **Use antd theming tokens** - Prefer antd tokens over legacy theming tokens
|
||||
- **Avoid custom css and styles** - Follow antd best practices and avoid styling and custom CSS whenever possible
|
||||
|
||||
### Testing Strategy Migration
|
||||
- **Prefer unit tests** over integration tests
|
||||
- **Prefer integration tests** over end-to-end tests
|
||||
- **Use Playwright for E2E tests** - Migrating from Cypress
|
||||
- **Cypress is deprecated** - Will be removed once migration is completed
|
||||
- **Use Jest + React Testing Library** for component testing
|
||||
- **Use `test()` instead of `describe()`** - Follow [avoid nesting when testing](https://kentcdodds.com/blog/avoid-nesting-when-youre-testing) principles
|
||||
|
||||
### Backend Type Safety
|
||||
- **Add type hints** - All new Python code needs proper typing
|
||||
- **MyPy compliance** - Run `pre-commit run mypy` to validate
|
||||
- **SQLAlchemy typing** - Use proper model annotations
|
||||
|
||||
### UUID Migration
|
||||
- **Prefer UUIDs over auto-incrementing IDs** - New models should use UUID primary keys
|
||||
- **External API exposure** - Use UUIDs in public APIs instead of internal integer IDs
|
||||
- **Existing models** - Add UUID fields alongside integer IDs for gradual migration
|
||||
|
||||
## Security and Threat Model
|
||||
|
||||
Before evaluating any code path for security issues, read [`SECURITY.md`](SECURITY.md). It is the canonical, authoritative source for Apache Superset's security model and is referenced by both human reporters and automated scanners.
|
||||
|
||||
In short, the test for whether a finding is in scope is one question:
|
||||
|
||||
> *Does it let a principal perform an action the role and capability matrix in `SECURITY.md` does not entitle them to?*
|
||||
|
||||
If yes, it is in scope. If no, it is not.
|
||||
|
||||
The three trust boundaries are:
|
||||
|
||||
1. **The Admin role** is a fully trusted operational principal. Anything an Admin can do through documented configuration, API, or UI is an intended capability, not a vulnerability.
|
||||
2. **The operator** owns deployment-time decisions (secrets, network exposure, feature-flag selection, connector and codec choices, notification destinations, third-party plugins). Misconfiguration at this layer is a deployment defect, not a Superset vulnerability.
|
||||
3. **The codebase** is responsible for enforcing the role and capability matrix wherever it exposes functionality to a principal: API routes, command and DAO layers, UI handlers, background jobs, and any other entry point. A missing or incorrect enforcement check is in scope no matter where it lives.
|
||||
|
||||
The security model assumes that operator-controlled infrastructure, including the metadata database, cache backends, message brokers, secret stores, and deployment environment, remains within the operator's trust boundary. Vulnerabilities must demonstrate a security boundary violation by an attacker who does not already control those systems.
|
||||
|
||||
Route-level authorization in this codebase uses one of three Flask-AppBuilder decorators depending on the route type:
|
||||
|
||||
- `@protect()` for REST API routes (`ModelRestApi` / `BaseApi`)
|
||||
- `@has_access_api` for legacy view routes
|
||||
- `@has_access` for legacy HTML view routes
|
||||
|
||||
Object-level authorization via `security_manager.raise_for_access(...)` applies to data-bearing resources: dashboards, charts, datasets and datasources, queries, database and table access, and query contexts. Other resources (annotations, tags, CSS templates, reports, RLS rules, and similar) rely on the route-level decorator plus DAO `base_filters` for ownership scoping; the absence of `raise_for_access` on these resources is by design, not a finding. Code that omits the per-object gate on a route that returns or mutates a specific data-bearing object is in scope; code that follows the correct pattern for its resource class can still contain injection, SSRF, XSS, or other classes of finding unrelated to authorization, which are evaluated separately.
|
||||
|
||||
The full role and capability matrix, in-scope and out-of-scope class lists, and CVE aggregation rules are in [`SECURITY.md`](SECURITY.md). Defer to that document for any specifics.
|
||||
|
||||
**Requirements for findings filed by automated tooling**
|
||||
|
||||
Automated scanners (LLM-based code scanners, static analyzers, dependency tools) that file findings against this codebase must, in each finding, name:
|
||||
|
||||
1. The specific role and capability matrix row in [`SECURITY.md`](SECURITY.md) the finding believes is violated.
|
||||
2. The principal the finding assumes the attacker holds (Public, Gamma, sql_lab, Alpha, Admin, Embedded guest token, or a custom role with explicit capability grants).
|
||||
|
||||
Findings that cannot identify both should be filed as questions, not vulnerabilities. This requirement exists to ensure every reported issue is testable against the published security model and to keep speculative or pattern-match-only reports out of the triage queue.
|
||||
|
||||
## Key Directories
|
||||
|
||||
```
|
||||
superset/
|
||||
├── superset/ # Python backend (Flask, SQLAlchemy)
|
||||
│ ├── views/api/ # REST API endpoints
|
||||
│ ├── models/ # Database models
|
||||
│ └── connectors/ # Database connections
|
||||
├── superset-frontend/src/ # React TypeScript frontend
|
||||
│ ├── components/ # Reusable components
|
||||
│ ├── explore/ # Chart builder
|
||||
│ ├── dashboard/ # Dashboard interface
|
||||
│ └── SqlLab/ # SQL editor
|
||||
├── superset-frontend/packages/
|
||||
│ └── superset-ui-core/ # UI component library (USE THIS)
|
||||
├── tests/ # Python/integration tests
|
||||
├── docs/ # Documentation (UPDATE FOR CHANGES)
|
||||
└── UPDATING.md # Breaking changes log
|
||||
```
|
||||
|
||||
## Code Standards
|
||||
|
||||
### TypeScript Frontend
|
||||
- **Avoid `any` types** - Use proper TypeScript, reuse existing types
|
||||
- **Functional components** with hooks
|
||||
- **@superset-ui/core** for UI components (not direct antd)
|
||||
- **Jest** for testing (NO Enzyme)
|
||||
- **Redux** for global state where it exists, hooks for local
|
||||
|
||||
### Python Backend
|
||||
- **Type hints required** for all new code
|
||||
- **MyPy compliant** - run `pre-commit run mypy`
|
||||
- **SQLAlchemy models** with proper typing
|
||||
- **pytest** for testing
|
||||
|
||||
### Apache License Headers
|
||||
- **New files require ASF license headers** - When creating new code files, include the standard Apache Software Foundation license header
|
||||
- **LLM instruction files are excluded** - Files like AGENTS.md, CLAUDE.md, etc. are in `.rat-excludes` to avoid header token overhead
|
||||
|
||||
### Code Comments
|
||||
- **Avoid time-specific language** - Don't use words like "now", "currently", "today" in code comments as they become outdated
|
||||
- **Write timeless comments** - Comments should remain accurate regardless of when they're read
|
||||
|
||||
## Documentation Requirements
|
||||
|
||||
- **docs/**: Update for any user-facing changes
|
||||
- **UPDATING.md**: Add breaking changes here
|
||||
- **Docstrings**: Required for new functions/classes
|
||||
|
||||
## Developer Portal: Storybook-to-MDX Documentation
|
||||
|
||||
The Developer Portal auto-generates MDX documentation from Storybook stories. **Stories are the single source of truth.**
|
||||
|
||||
### Core Philosophy
|
||||
- **Fix issues in the STORY, not the generator** - When something doesn't render correctly, update the story file first
|
||||
- **Generator should be lightweight** - It extracts and passes through data; avoid special cases
|
||||
- **Stories define everything** - Props, controls, galleries, examples all come from story metadata
|
||||
|
||||
### Story Requirements for Docs Generation
|
||||
- Use `export default { title: '...' }` (inline), not `const meta = ...; export default meta;`
|
||||
- Name interactive stories `Interactive${ComponentName}` (e.g., `InteractiveButton`)
|
||||
- Define `args` for default prop values
|
||||
- Define `argTypes` at the story level (not meta level) with control types and descriptions
|
||||
- Use `parameters.docs.gallery` for size×style variant grids
|
||||
- Use `parameters.docs.sampleChildren` for components that need children
|
||||
- Use `parameters.docs.liveExample` for custom live code blocks
|
||||
- Use `parameters.docs.staticProps` for complex object props that can't be parsed inline
|
||||
|
||||
### Generator Location
|
||||
- Script: `docs/scripts/generate-superset-components.mjs`
|
||||
- Wrapper: `docs/src/components/StorybookWrapper.jsx`
|
||||
- Output: `docs/developer_portal/components/`
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Security & Features
|
||||
- **Security model**: see the top-level [Security and Threat Model](#security-and-threat-model) section and [`SECURITY.md`](SECURITY.md)
|
||||
- **RBAC**: Role-based access via Flask-AppBuilder
|
||||
- **Feature flags**: Control feature rollouts
|
||||
- **Row-level security**: SQL-based data access control
|
||||
|
||||
## Test Utilities
|
||||
|
||||
### Python Test Helpers
|
||||
- **`SupersetTestCase`** - Base class in `tests/integration_tests/base_tests.py`
|
||||
- **`@with_config`** - Config mocking decorator
|
||||
- **`@with_feature_flags`** - Feature flag testing
|
||||
- **`login_as()`, `login_as_admin()`** - Authentication helpers
|
||||
- **`create_dashboard()`, `create_slice()`** - Data setup utilities
|
||||
|
||||
### TypeScript Test Helpers
|
||||
- **`superset-frontend/spec/helpers/testing-library.tsx`** - Custom render() with providers
|
||||
- **`createWrapper()`** - Redux/Router/Theme wrapper
|
||||
- **`selectOption()`** - Select component helper
|
||||
- **React Testing Library** - NO Enzyme (removed)
|
||||
|
||||
### Test Database Patterns
|
||||
- **Mock patterns**: Use `MagicMock()` for config objects, avoid `AsyncMock` for synchronous code
|
||||
- **API tests**: Update expected columns when adding new model fields
|
||||
|
||||
### Running Tests
|
||||
```bash
|
||||
# Frontend
|
||||
npm run test # All tests
|
||||
npm run test -- filename.test.tsx # Single file
|
||||
|
||||
# E2E Tests (Playwright - NEW)
|
||||
npm run playwright:test # All Playwright tests
|
||||
npm run playwright:ui # Interactive UI mode
|
||||
npm run playwright:headed # See browser during tests
|
||||
npx playwright test tests/auth/login.spec.ts # Single file
|
||||
npm run playwright:debug tests/auth/login.spec.ts # Debug specific file
|
||||
|
||||
# E2E Tests (Cypress - DEPRECATED)
|
||||
cd superset-frontend/cypress-base
|
||||
npm run cypress-run-chrome # All Cypress tests (headless)
|
||||
npm run cypress-debug # Interactive Cypress UI
|
||||
|
||||
# Backend
|
||||
pytest # All tests
|
||||
pytest tests/unit_tests/specific_test.py # Single file
|
||||
pytest tests/unit_tests/ # Directory
|
||||
|
||||
# If pytest fails with database/setup issues, ask the user to run test environment setup
|
||||
```
|
||||
|
||||
## Environment Validation
|
||||
|
||||
**Quick Setup Check (run this first):**
|
||||
|
||||
```bash
|
||||
# Verify Superset is running
|
||||
curl -f http://localhost:8088/health || echo "❌ Setup required - see https://superset.apache.org/docs/contributing/development#working-with-llms"
|
||||
```
|
||||
|
||||
**If health checks fail:**
|
||||
"It appears you aren't set up properly. Please refer to the [Working with LLMs](https://superset.apache.org/docs/contributing/development#working-with-llms) section in the development docs for setup instructions."
|
||||
|
||||
**Key Project Files:**
|
||||
- `superset-frontend/package.json` - Frontend build scripts (`npm run dev` on port 9000, `npm run test`, `npm run lint`)
|
||||
- `pyproject.toml` - Python tooling (ruff, mypy configs)
|
||||
- `requirements/` folder - Python dependencies (base.txt, development.txt)
|
||||
|
||||
## SQLAlchemy Query Best Practices
|
||||
- **Use negation operator**: `~Model.field` instead of `== False` to avoid ruff E712 errors
|
||||
- **Example**: `~Model.is_active` instead of `Model.is_active == False`
|
||||
|
||||
## Pull Request Guidelines
|
||||
|
||||
**When creating pull requests:**
|
||||
|
||||
1. **Read the current PR template**: Always check `.github/PULL_REQUEST_TEMPLATE.md` for the latest format
|
||||
2. **Use the template sections**: Include all sections from the template (SUMMARY, BEFORE/AFTER, TESTING INSTRUCTIONS, ADDITIONAL INFORMATION)
|
||||
3. **Follow PR title conventions**: Use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
|
||||
- Format: `type(scope): description`
|
||||
- Example: `fix(dashboard): load charts correctly`
|
||||
- Types: `fix`, `feat`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`
|
||||
|
||||
**Important**: Always reference the actual template file at `.github/PULL_REQUEST_TEMPLATE.md` instead of using cached content, as the template may be updated over time.
|
||||
|
||||
## Pre-commit Validation
|
||||
|
||||
**Use pre-commit hooks for quality validation:**
|
||||
|
||||
```bash
|
||||
# Install hooks
|
||||
pre-commit install
|
||||
|
||||
# IMPORTANT: Stage your changes first!
|
||||
git add . # Pre-commit only checks staged files
|
||||
|
||||
# Quick validation (faster than --all-files)
|
||||
pre-commit run # Staged files only
|
||||
pre-commit run mypy # Python type checking
|
||||
pre-commit run prettier # Code formatting
|
||||
pre-commit run eslint # Frontend linting
|
||||
```
|
||||
|
||||
**Important pre-commit usage notes:**
|
||||
- **Stage files first**: Run `git add .` before `pre-commit run` to check only changed files (much faster)
|
||||
- **Virtual environment**: Activate your Python virtual environment before running pre-commit
|
||||
```bash
|
||||
# Common virtual environment locations (yours may differ):
|
||||
source .venv/bin/activate # if using .venv
|
||||
source venv/bin/activate # if using venv
|
||||
source ~/venvs/superset/bin/activate # if using a central location
|
||||
```
|
||||
If you get a "command not found" error, ask the user which virtual environment to activate
|
||||
- **Auto-fixes**: Some hooks auto-fix issues (e.g., trailing whitespace). Re-run after fixes are applied
|
||||
|
||||
## Common File Patterns
|
||||
|
||||
### API Structure
|
||||
- **`/api.py`** - REST endpoints with decorators and OpenAPI docstrings
|
||||
- **`/schemas.py`** - Marshmallow validation schemas for OpenAPI spec
|
||||
- **`/commands/`** - Business logic classes with @transaction() decorators
|
||||
- **`/models/`** - SQLAlchemy database models
|
||||
- **OpenAPI docs**: Auto-generated at `/swagger/v1` from docstrings and schemas
|
||||
|
||||
### Migration Files
|
||||
- **Location**: `superset/migrations/versions/`
|
||||
- **Naming**: `YYYY-MM-DD_HH-MM_hash_description.py`
|
||||
- **Utilities**: Use helpers from `superset.migrations.shared.utils` for database compatibility
|
||||
- **Pattern**: Import utilities instead of raw SQLAlchemy operations
|
||||
|
||||
## Platform-Specific Instructions
|
||||
|
||||
- **[CLAUDE.md](CLAUDE.md)** - For Claude/Anthropic tools
|
||||
- **[.github/copilot-instructions.md](.github/copilot-instructions.md)** - For GitHub Copilot
|
||||
- **[GEMINI.md](GEMINI.md)** - For Google Gemini tools
|
||||
- **[GPT.md](GPT.md)** - For OpenAI/ChatGPT tools
|
||||
- **[.cursor/rules/dev-standard.mdc](.cursor/rules/dev-standard.mdc)** - For Cursor editor
|
||||
|
||||
---
|
||||
|
||||
**LLM Note**: This codebase is actively modernizing toward full TypeScript and type safety. Always run `pre-commit run` to validate changes. Follow the ongoing refactors section to avoid deprecated patterns.
|
||||
@@ -49,4 +49,3 @@ under the License.
|
||||
- [4.1.3](./CHANGELOG/4.1.3.md)
|
||||
- [4.1.4](./CHANGELOG/4.1.4.md)
|
||||
- [5.0.0](./CHANGELOG/5.0.0.md)
|
||||
- [6.0.0](./CHANGELOG/6.0.0.md)
|
||||
|
||||
1062
CHANGELOG/6.0.0.md
1062
CHANGELOG/6.0.0.md
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
@@ -16,23 +16,9 @@
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
# Contributing to Apache Superset
|
||||
|
||||
Contributions are welcome and are greatly appreciated! Every
|
||||
little bit helps, and credit will always be given.
|
||||
|
||||
## Developer Portal
|
||||
|
||||
All developer and contribution documentation has moved to the Apache Superset Developer Portal:
|
||||
|
||||
**[📚 View the Developer Portal →](https://superset.apache.org/developer_portal/)**
|
||||
|
||||
The Developer Portal includes comprehensive guides for:
|
||||
- [Contributing Overview](https://superset.apache.org/developer_portal/contributing/overview)
|
||||
- [Development Setup](https://superset.apache.org/developer_portal/contributing/development-setup)
|
||||
- [Submitting Pull Requests](https://superset.apache.org/developer_portal/contributing/submitting-pr)
|
||||
- [Contribution Guidelines](https://superset.apache.org/developer_portal/contributing/guidelines)
|
||||
- [Code Review Process](https://superset.apache.org/developer_portal/contributing/code-review)
|
||||
- [Development How-tos](https://superset.apache.org/developer_portal/contributing/howtos)
|
||||
|
||||
Source for the Developer Portal documentation is [located here](https://github.com/apache/superset/tree/master/docs/developer_portal).
|
||||
All matters related to contributions have moved to [this section of
|
||||
the official Superset documentation](https://superset.apache.org/docs/contributing/). Source for the documentation is
|
||||
[located here](https://github.com/apache/superset/tree/master/docs/docs).
|
||||
|
||||
36
Dockerfile
36
Dockerfile
@@ -18,7 +18,7 @@
|
||||
######################################################################
|
||||
# Node stage to deal with static asset construction
|
||||
######################################################################
|
||||
ARG PY_VER=3.11.14-slim-trixie
|
||||
ARG PY_VER=3.11.13-slim-trixie
|
||||
|
||||
# If BUILDPLATFORM is null, set it to 'amd64' (or leave as is otherwise).
|
||||
ARG BUILDPLATFORM=${BUILDPLATFORM:-amd64}
|
||||
@@ -29,7 +29,7 @@ ARG BUILD_TRANSLATIONS="false"
|
||||
######################################################################
|
||||
# superset-node-ci used as a base for building frontend assets and CI
|
||||
######################################################################
|
||||
FROM --platform=${BUILDPLATFORM} node:22-trixie-slim AS superset-node-ci
|
||||
FROM --platform=${BUILDPLATFORM} node:20-trixie-slim AS superset-node-ci
|
||||
ARG BUILD_TRANSLATIONS
|
||||
ENV BUILD_TRANSLATIONS=${BUILD_TRANSLATIONS}
|
||||
ARG DEV_MODE="false" # Skip frontend build in dev mode
|
||||
@@ -55,13 +55,6 @@ WORKDIR /app/superset-frontend
|
||||
RUN mkdir -p /app/superset/static/assets \
|
||||
/app/superset/translations
|
||||
|
||||
# Harden `npm ci` against transient npm-registry network blips (e.g. ECONNRESET),
|
||||
# which otherwise fail the entire multi-platform image build with no retry.
|
||||
ENV npm_config_fetch_retries=5 \
|
||||
npm_config_fetch_retry_mintimeout=20000 \
|
||||
npm_config_fetch_retry_maxtimeout=120000 \
|
||||
npm_config_fetch_timeout=600000
|
||||
|
||||
# Mount package files and install dependencies if not in dev mode
|
||||
# NOTE: we mount packages and plugins as they are referenced in package.json as workspaces
|
||||
# ideally we'd COPY only their package.json. Here npm ci will be cached as long
|
||||
@@ -120,7 +113,7 @@ RUN useradd --user-group -d ${SUPERSET_HOME} -m --no-log-init --shell /bin/bash
|
||||
# Some bash scripts needed throughout the layers
|
||||
COPY --chmod=755 docker/*.sh /app/docker/
|
||||
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
||||
RUN pip install --no-cache-dir --upgrade uv
|
||||
|
||||
# Using uv as it's faster/simpler than pip
|
||||
RUN uv venv /app/.venv
|
||||
@@ -150,6 +143,9 @@ RUN if [ "${BUILD_TRANSLATIONS}" = "true" ]; then \
|
||||
######################################################################
|
||||
FROM python-base AS python-common
|
||||
|
||||
# Build arg to pre-populate examples DuckDB file
|
||||
ARG LOAD_EXAMPLES_DUCKDB="false"
|
||||
|
||||
ENV SUPERSET_HOME="/app/superset_home" \
|
||||
HOME="/app/superset_home" \
|
||||
SUPERSET_ENV="production" \
|
||||
@@ -161,7 +157,7 @@ ENV SUPERSET_HOME="/app/superset_home" \
|
||||
COPY --chmod=755 docker/entrypoints /app/docker/entrypoints
|
||||
|
||||
WORKDIR /app
|
||||
# Set up necessary directories
|
||||
# Set up necessary directories and user
|
||||
RUN mkdir -p \
|
||||
${PYTHONPATH} \
|
||||
superset/static \
|
||||
@@ -172,8 +168,6 @@ RUN mkdir -p \
|
||||
&& touch superset/static/version_info.json
|
||||
|
||||
# Install Playwright and optionally setup headless browsers
|
||||
ENV PLAYWRIGHT_BROWSERS_PATH=/usr/local/share/playwright-browsers
|
||||
|
||||
ARG INCLUDE_CHROMIUM="false"
|
||||
ARG INCLUDE_FIREFOX="false"
|
||||
RUN --mount=type=cache,target=${SUPERSET_HOME}/.cache/uv \
|
||||
@@ -203,14 +197,20 @@ RUN /app/docker/apt-install.sh \
|
||||
libecpg-dev \
|
||||
libldap2-dev
|
||||
|
||||
# Create data directory for DuckDB examples database
|
||||
# The database file will be created at runtime when examples are loaded from Parquet files
|
||||
RUN mkdir -p /app/data && chown -R superset:superset /app/data
|
||||
# Pre-load examples DuckDB file if requested
|
||||
RUN if [ "$LOAD_EXAMPLES_DUCKDB" = "true" ]; then \
|
||||
mkdir -p /app/data && \
|
||||
echo "Downloading pre-built examples.duckdb..." && \
|
||||
curl -L -o /app/data/examples.duckdb \
|
||||
"https://raw.githubusercontent.com/apache-superset/examples-data/master/examples.duckdb" && \
|
||||
chown -R superset:superset /app/data; \
|
||||
else \
|
||||
mkdir -p /app/data && \
|
||||
chown -R superset:superset /app/data; \
|
||||
fi
|
||||
|
||||
# Copy compiled things from previous stages
|
||||
COPY --from=superset-node /app/superset/static/assets superset/static/assets
|
||||
# Copy service.worker.js optionall as it doesn't exist when DEV_MODE=true
|
||||
COPY --from=superset-node /app/superset/static/service-worker.j[s] superset/static/service-worker.js
|
||||
|
||||
# TODO, when the next version comes out, use --exclude superset/translations
|
||||
COPY superset superset
|
||||
|
||||
20
INSTALL.md
20
INSTALL.md
@@ -16,20 +16,8 @@ KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
# Installing Apache Superset
|
||||
# INSTALL / BUILD instructions for Apache Superset
|
||||
|
||||
For comprehensive installation instructions, please see the Apache Superset documentation:
|
||||
|
||||
**[📚 Installation Guide →](https://superset.apache.org/docs/installation/installation-methods)**
|
||||
|
||||
The documentation covers:
|
||||
- [Docker Compose](https://superset.apache.org/docs/installation/docker-compose) (recommended for development)
|
||||
- [Kubernetes / Helm](https://superset.apache.org/docs/installation/kubernetes)
|
||||
- [PyPI](https://superset.apache.org/docs/installation/pypi)
|
||||
- [Docker Builds](https://superset.apache.org/docs/installation/docker-builds)
|
||||
- [Architecture Overview](https://superset.apache.org/docs/installation/architecture)
|
||||
|
||||
## Building from Source
|
||||
|
||||
For building from a source release tarball, see the Dockerfile at:
|
||||
`RELEASING/Dockerfile.from_local_tarball`
|
||||
At this time, the docker file at RELEASING/Dockerfile.from_local_tarball
|
||||
constitutes the recipe on how to get to a working release from a source
|
||||
release tarball.
|
||||
|
||||
194
LLMS.md
Normal file
194
LLMS.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# LLM Context Guide for Apache Superset
|
||||
|
||||
Apache Superset is a data visualization platform with Flask/Python backend and React/TypeScript frontend.
|
||||
|
||||
## ⚠️ CRITICAL: Ongoing Refactors (What NOT to Do)
|
||||
|
||||
**These migrations are actively happening - avoid deprecated patterns:**
|
||||
|
||||
### Frontend Modernization
|
||||
- **NO `any` types** - Use proper TypeScript types
|
||||
- **NO JavaScript files** - Convert to TypeScript (.ts/.tsx)
|
||||
- **Use @superset-ui/core** - Don't import Ant Design directly, prefer Ant Design component wrappers from @superset-ui/core/components
|
||||
- **Use antd theming tokens** - Prefer antd tokens over legacy theming tokens
|
||||
- **Avoid custom css and styles** - Follow antd best practices and avoid styling and custom CSS whenever possible
|
||||
|
||||
### Testing Strategy Migration
|
||||
- **Prefer unit tests** over integration tests
|
||||
- **Prefer integration tests** over Cypress end-to-end tests
|
||||
- **Cypress is last resort** - Actively moving away from Cypress
|
||||
- **Use Jest + React Testing Library** for component testing
|
||||
- **Use `test()` instead of `describe()`** - Follow [avoid nesting when testing](https://kentcdodds.com/blog/avoid-nesting-when-youre-testing) principles
|
||||
|
||||
### Backend Type Safety
|
||||
- **Add type hints** - All new Python code needs proper typing
|
||||
- **MyPy compliance** - Run `pre-commit run mypy` to validate
|
||||
- **SQLAlchemy typing** - Use proper model annotations
|
||||
|
||||
### UUID Migration
|
||||
- **Prefer UUIDs over auto-incrementing IDs** - New models should use UUID primary keys
|
||||
- **External API exposure** - Use UUIDs in public APIs instead of internal integer IDs
|
||||
- **Existing models** - Add UUID fields alongside integer IDs for gradual migration
|
||||
|
||||
## Key Directories
|
||||
|
||||
```
|
||||
superset/
|
||||
├── superset/ # Python backend (Flask, SQLAlchemy)
|
||||
│ ├── views/api/ # REST API endpoints
|
||||
│ ├── models/ # Database models
|
||||
│ └── connectors/ # Database connections
|
||||
├── superset-frontend/src/ # React TypeScript frontend
|
||||
│ ├── components/ # Reusable components
|
||||
│ ├── explore/ # Chart builder
|
||||
│ ├── dashboard/ # Dashboard interface
|
||||
│ └── SqlLab/ # SQL editor
|
||||
├── superset-frontend/packages/
|
||||
│ └── superset-ui-core/ # UI component library (USE THIS)
|
||||
├── tests/ # Python/integration tests
|
||||
├── docs/ # Documentation (UPDATE FOR CHANGES)
|
||||
└── UPDATING.md # Breaking changes log
|
||||
```
|
||||
|
||||
## Code Standards
|
||||
|
||||
### TypeScript Frontend
|
||||
- **Avoid `any` types** - Use proper TypeScript, reuse existing types
|
||||
- **Functional components** with hooks
|
||||
- **@superset-ui/core** for UI components (not direct antd)
|
||||
- **Jest** for testing (NO Enzyme)
|
||||
- **Redux** for global state where it exists, hooks for local
|
||||
|
||||
### Python Backend
|
||||
- **Type hints required** for all new code
|
||||
- **MyPy compliant** - run `pre-commit run mypy`
|
||||
- **SQLAlchemy models** with proper typing
|
||||
- **pytest** for testing
|
||||
|
||||
### Apache License Headers
|
||||
- **New files require ASF license headers** - When creating new code files, include the standard Apache Software Foundation license header
|
||||
- **LLM instruction files are excluded** - Files like LLMS.md, CLAUDE.md, etc. are in `.rat-excludes` to avoid header token overhead
|
||||
|
||||
## Documentation Requirements
|
||||
|
||||
- **docs/**: Update for any user-facing changes
|
||||
- **UPDATING.md**: Add breaking changes here
|
||||
- **Docstrings**: Required for new functions/classes
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Security & Features
|
||||
- **RBAC**: Role-based access via Flask-AppBuilder
|
||||
- **Feature flags**: Control feature rollouts
|
||||
- **Row-level security**: SQL-based data access control
|
||||
|
||||
## Test Utilities
|
||||
|
||||
### Python Test Helpers
|
||||
- **`SupersetTestCase`** - Base class in `tests/integration_tests/base_tests.py`
|
||||
- **`@with_config`** - Config mocking decorator
|
||||
- **`@with_feature_flags`** - Feature flag testing
|
||||
- **`login_as()`, `login_as_admin()`** - Authentication helpers
|
||||
- **`create_dashboard()`, `create_slice()`** - Data setup utilities
|
||||
|
||||
### TypeScript Test Helpers
|
||||
- **`superset-frontend/spec/helpers/testing-library.tsx`** - Custom render() with providers
|
||||
- **`createWrapper()`** - Redux/Router/Theme wrapper
|
||||
- **`selectOption()`** - Select component helper
|
||||
- **React Testing Library** - NO Enzyme (removed)
|
||||
|
||||
### Test Database Patterns
|
||||
- **Mock patterns**: Use `MagicMock()` for config objects, avoid `AsyncMock` for synchronous code
|
||||
- **API tests**: Update expected columns when adding new model fields
|
||||
|
||||
### Running Tests
|
||||
```bash
|
||||
# Frontend
|
||||
npm run test # All tests
|
||||
npm run test -- filename.test.tsx # Single file
|
||||
|
||||
# Backend
|
||||
pytest # All tests
|
||||
pytest tests/unit_tests/specific_test.py # Single file
|
||||
pytest tests/unit_tests/ # Directory
|
||||
|
||||
# If pytest fails with database/setup issues, ask the user to run test environment setup
|
||||
```
|
||||
|
||||
## Environment Validation
|
||||
|
||||
**Quick Setup Check (run this first):**
|
||||
|
||||
```bash
|
||||
# Verify Superset is running
|
||||
curl -f http://localhost:8088/health || echo "❌ Setup required - see https://superset.apache.org/docs/contributing/development#working-with-llms"
|
||||
```
|
||||
|
||||
**If health checks fail:**
|
||||
"It appears you aren't set up properly. Please refer to the [Working with LLMs](https://superset.apache.org/docs/contributing/development#working-with-llms) section in the development docs for setup instructions."
|
||||
|
||||
**Key Project Files:**
|
||||
- `superset-frontend/package.json` - Frontend build scripts (`npm run dev` on port 9000, `npm run test`, `npm run lint`)
|
||||
- `pyproject.toml` - Python tooling (ruff, mypy configs)
|
||||
- `requirements/` folder - Python dependencies (base.txt, development.txt)
|
||||
|
||||
## SQLAlchemy Query Best Practices
|
||||
- **Use negation operator**: `~Model.field` instead of `== False` to avoid ruff E712 errors
|
||||
- **Example**: `~Model.is_active` instead of `Model.is_active == False`
|
||||
|
||||
## Pre-commit Validation
|
||||
|
||||
**Use pre-commit hooks for quality validation:**
|
||||
|
||||
```bash
|
||||
# Install hooks
|
||||
pre-commit install
|
||||
|
||||
# IMPORTANT: Stage your changes first!
|
||||
git add . # Pre-commit only checks staged files
|
||||
|
||||
# Quick validation (faster than --all-files)
|
||||
pre-commit run # Staged files only
|
||||
pre-commit run mypy # Python type checking
|
||||
pre-commit run prettier # Code formatting
|
||||
pre-commit run eslint # Frontend linting
|
||||
```
|
||||
|
||||
**Important pre-commit usage notes:**
|
||||
- **Stage files first**: Run `git add .` before `pre-commit run` to check only changed files (much faster)
|
||||
- **Virtual environment**: Activate your Python virtual environment before running pre-commit
|
||||
```bash
|
||||
# Common virtual environment locations (yours may differ):
|
||||
source .venv/bin/activate # if using .venv
|
||||
source venv/bin/activate # if using venv
|
||||
source ~/venvs/superset/bin/activate # if using a central location
|
||||
```
|
||||
If you get a "command not found" error, ask the user which virtual environment to activate
|
||||
- **Auto-fixes**: Some hooks auto-fix issues (e.g., trailing whitespace). Re-run after fixes are applied
|
||||
|
||||
## Common File Patterns
|
||||
|
||||
### API Structure
|
||||
- **`/api.py`** - REST endpoints with decorators and OpenAPI docstrings
|
||||
- **`/schemas.py`** - Marshmallow validation schemas for OpenAPI spec
|
||||
- **`/commands/`** - Business logic classes with @transaction() decorators
|
||||
- **`/models/`** - SQLAlchemy database models
|
||||
- **OpenAPI docs**: Auto-generated at `/swagger/v1` from docstrings and schemas
|
||||
|
||||
### Migration Files
|
||||
- **Location**: `superset/migrations/versions/`
|
||||
- **Naming**: `YYYY-MM-DD_HH-MM_hash_description.py`
|
||||
- **Utilities**: Use helpers from `superset.migrations.shared.utils` for database compatibility
|
||||
- **Pattern**: Import utilities instead of raw SQLAlchemy operations
|
||||
|
||||
## Platform-Specific Instructions
|
||||
|
||||
- **[CLAUDE.md](CLAUDE.md)** - For Claude/Anthropic tools
|
||||
- **[.github/copilot-instructions.md](.github/copilot-instructions.md)** - For GitHub Copilot
|
||||
- **[GEMINI.md](GEMINI.md)** - For Google Gemini tools
|
||||
- **[GPT.md](GPT.md)** - For OpenAI/ChatGPT tools
|
||||
- **[.cursor/rules/dev-standard.mdc](.cursor/rules/dev-standard.mdc)** - For Cursor editor
|
||||
|
||||
---
|
||||
|
||||
**LLM Note**: This codebase is actively modernizing toward full TypeScript and type safety. Always run `pre-commit run` to validate changes. Follow the ongoing refactors section to avoid deprecated patterns.
|
||||
27
Makefile
27
Makefile
@@ -18,7 +18,7 @@
|
||||
# Python version installed; we need 3.10-3.11
|
||||
PYTHON=`command -v python3.11 || command -v python3.10`
|
||||
|
||||
.PHONY: install superset venv pre-commit up down logs ps nuke ports open
|
||||
.PHONY: install superset venv pre-commit
|
||||
|
||||
install: superset pre-commit
|
||||
|
||||
@@ -112,28 +112,3 @@ report-celery-beat:
|
||||
|
||||
admin-user:
|
||||
superset fab create-admin
|
||||
|
||||
# Docker Compose with auto-assigned ports (for running multiple instances)
|
||||
up:
|
||||
./scripts/docker-compose-up.sh
|
||||
|
||||
up-detached:
|
||||
./scripts/docker-compose-up.sh -d
|
||||
|
||||
down:
|
||||
./scripts/docker-compose-up.sh down
|
||||
|
||||
logs:
|
||||
./scripts/docker-compose-up.sh logs -f
|
||||
|
||||
ps:
|
||||
./scripts/docker-compose-up.sh ps
|
||||
|
||||
nuke:
|
||||
./scripts/docker-compose-up.sh nuke
|
||||
|
||||
ports:
|
||||
./scripts/docker-compose-up.sh ports
|
||||
|
||||
open:
|
||||
./scripts/docker-compose-up.sh open
|
||||
|
||||
133
README.md
133
README.md
@@ -23,12 +23,8 @@ under the License.
|
||||
[](https://github.com/apache/superset/releases/latest)
|
||||
[](https://github.com/apache/superset/actions)
|
||||
[](https://badge.fury.io/py/apache_superset)
|
||||
[](https://codecov.io/github/apache/superset)
|
||||
[](https://pypi.python.org/pypi/apache_superset)
|
||||
[](https://github.com/apache/superset/stargazers)
|
||||
[](https://github.com/apache/superset/graphs/contributors)
|
||||
[](https://github.com/apache/superset/commits/master)
|
||||
[](https://github.com/apache/superset/issues)
|
||||
[](https://github.com/apache/superset/pulls)
|
||||
[](http://bit.ly/join-superset-slack)
|
||||
[](https://superset.apache.org)
|
||||
|
||||
@@ -48,18 +44,14 @@ under the License.
|
||||
|
||||
A modern, enterprise-ready business intelligence web application.
|
||||
|
||||
### Documentation
|
||||
|
||||
- **[User Guide](https://superset.apache.org/user-docs/)** — For analysts and business users. Explore data, build charts, create dashboards, and connect databases.
|
||||
- **[Administrator Guide](https://superset.apache.org/admin-docs/)** — Install, configure, and operate Superset. Covers security, scaling, and database drivers.
|
||||
- **[Developer Guide](https://superset.apache.org/developer-docs/)** — Contribute to Superset or build on its REST API and extension framework.
|
||||
|
||||
[**Why Superset?**](#why-superset) |
|
||||
[**Supported Databases**](#supported-databases) |
|
||||
[**Installation and Configuration**](#installation-and-configuration) |
|
||||
[**Release Notes**](https://github.com/apache/superset/blob/master/RELEASING/README.md#release-notes-for-recent-releases) |
|
||||
[**Get Involved**](#get-involved) |
|
||||
[**Contributor Guide**](#contributor-guide) |
|
||||
[**Resources**](#resources) |
|
||||
[**Organizations Using Superset**](https://superset.apache.org/inTheWild)
|
||||
[**Organizations Using Superset**](https://github.com/apache/superset/blob/master/RESOURCES/INTHEWILD.md)
|
||||
|
||||
## Why Superset?
|
||||
|
||||
@@ -93,7 +85,7 @@ Superset provides:
|
||||
|
||||
**Craft Beautiful, Dynamic Dashboards**
|
||||
|
||||
<kbd><img title="View Dashboards" src="https://superset.apache.org/img/screenshots/dashboard.jpg"/></kbd><br/>
|
||||
<kbd><img title="View Dashboards" src="https://superset.apache.org/img/screenshots/slack_dash.jpg"/></kbd><br/>
|
||||
|
||||
**No-Code Chart Builder**
|
||||
|
||||
@@ -105,77 +97,51 @@ Superset provides:
|
||||
|
||||
## Supported Databases
|
||||
|
||||
Superset can query data from any SQL-speaking datastore or data engine (Presto, Trino, Athena, [and more](https://superset.apache.org/docs/databases)) that has a Python DB-API driver and a SQLAlchemy dialect.
|
||||
Superset can query data from any SQL-speaking datastore or data engine (Presto, Trino, Athena, [and more](https://superset.apache.org/docs/configuration/databases)) that has a Python DB-API driver and a SQLAlchemy dialect.
|
||||
|
||||
Here are some of the major database solutions that are supported:
|
||||
|
||||
<!-- SUPPORTED_DATABASES_START -->
|
||||
<p align="center">
|
||||
<a href="https://superset.apache.org/docs/databases/supported/amazon-athena" title="Amazon Athena"><img src="docs/static/img/databases/amazon-athena.jpg" alt="Amazon Athena" width="76" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/amazon-dynamodb" title="Amazon DynamoDB"><img src="docs/static/img/databases/aws.png" alt="Amazon DynamoDB" width="40" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/amazon-redshift" title="Amazon Redshift"><img src="docs/static/img/databases/redshift.png" alt="Amazon Redshift" width="100" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/apache-doris" title="Apache Doris"><img src="docs/static/img/databases/doris.png" alt="Apache Doris" width="103" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/apache-drill" title="Apache Drill"><img src="docs/static/img/databases/apache-drill.png" alt="Apache Drill" width="81" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/apache-druid" title="Apache Druid"><img src="docs/static/img/databases/druid.png" alt="Apache Druid" width="117" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/apache-hive" title="Apache Hive"><img src="docs/static/img/databases/apache-hive.svg" alt="Apache Hive" width="44" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/apache-impala" title="Apache Impala"><img src="docs/static/img/databases/apache-impala.png" alt="Apache Impala" width="21" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/apache-kylin" title="Apache Kylin"><img src="docs/static/img/databases/apache-kylin.png" alt="Apache Kylin" width="44" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/apache-pinot" title="Apache Pinot"><img src="docs/static/img/databases/apache-pinot.svg" alt="Apache Pinot" width="76" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/apache-solr" title="Apache Solr"><img src="docs/static/img/databases/apache-solr.png" alt="Apache Solr" width="79" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/apache-spark-sql" title="Apache Spark SQL"><img src="docs/static/img/databases/apache-spark.png" alt="Apache Spark SQL" width="75" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/ascend" title="Ascend"><img src="docs/static/img/databases/ascend.webp" alt="Ascend" width="117" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/aurora-mysql-data-api" title="Aurora MySQL (Data API)"><img src="docs/static/img/databases/mysql.png" alt="Aurora MySQL (Data API)" width="77" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/aurora-postgresql-data-api" title="Aurora PostgreSQL (Data API)"><img src="docs/static/img/databases/postgresql.svg" alt="Aurora PostgreSQL (Data API)" width="76" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/azure-data-explorer" title="Azure Data Explorer"><img src="docs/static/img/databases/kusto.png" alt="Azure Data Explorer" width="40" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/azure-synapse" title="Azure Synapse"><img src="docs/static/img/databases/azure.svg" alt="Azure Synapse" width="40" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/clickhouse" title="ClickHouse"><img src="docs/static/img/databases/clickhouse.png" alt="ClickHouse" width="150" height="37" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/cloudflare-d1" title="Cloudflare D1"><img src="docs/static/img/databases/cloudflare.png" alt="Cloudflare D1" width="40" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/cockroachdb" title="CockroachDB"><img src="docs/static/img/databases/cockroachdb.png" alt="CockroachDB" width="150" height="24" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/couchbase" title="Couchbase"><img src="docs/static/img/databases/couchbase.svg" alt="Couchbase" width="150" height="35" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/cratedb" title="CrateDB"><img src="docs/static/img/databases/cratedb.svg" alt="CrateDB" width="180" height="24" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/databend" title="Databend"><img src="docs/static/img/databases/databend.png" alt="Databend" width="100" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/databricks" title="Databricks"><img src="docs/static/img/databases/databricks.png" alt="Databricks" width="152" height="24" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/denodo" title="Denodo"><img src="docs/static/img/databases/denodo.png" alt="Denodo" width="138" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/dremio" title="Dremio"><img src="docs/static/img/databases/dremio.png" alt="Dremio" width="126" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/duckdb" title="DuckDB"><img src="docs/static/img/databases/duckdb.png" alt="DuckDB" width="52" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/elasticsearch" title="Elasticsearch"><img src="docs/static/img/databases/elasticsearch.png" alt="Elasticsearch" width="40" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/exasol" title="Exasol"><img src="docs/static/img/databases/exasol.png" alt="Exasol" width="72" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/firebird" title="Firebird"><img src="docs/static/img/databases/firebird.png" alt="Firebird" width="100" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/firebolt" title="Firebolt"><img src="docs/static/img/databases/firebolt.png" alt="Firebolt" width="100" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/google-bigquery" title="Google BigQuery"><img src="docs/static/img/databases/google-big-query.svg" alt="Google BigQuery" width="76" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/google-sheets" title="Google Sheets"><img src="docs/static/img/databases/google-sheets.svg" alt="Google Sheets" width="76" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/greenplum" title="Greenplum"><img src="docs/static/img/databases/greenplum.png" alt="Greenplum" width="124" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/hologres" title="Hologres"><img src="docs/static/img/databases/hologres.png" alt="Hologres" width="44" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/ibm-db2" title="IBM Db2"><img src="docs/static/img/databases/ibm-db2.svg" alt="IBM Db2" width="91" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/ibm-netezza-performance-server" title="IBM Netezza Performance Server"><img src="docs/static/img/databases/netezza.png" alt="IBM Netezza Performance Server" width="40" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/mariadb" title="MariaDB"><img src="docs/static/img/databases/mariadb.png" alt="MariaDB" width="150" height="37" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/microsoft-sql-server" title="Microsoft SQL Server"><img src="docs/static/img/databases/msql.png" alt="Microsoft SQL Server" width="50" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/monetdb" title="MonetDB"><img src="docs/static/img/databases/monet-db.png" alt="MonetDB" width="100" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/mongodb" title="MongoDB"><img src="docs/static/img/databases/mongodb.png" alt="MongoDB" width="150" height="38" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/motherduck" title="MotherDuck"><img src="docs/static/img/databases/motherduck.png" alt="MotherDuck" width="40" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/oceanbase" title="OceanBase"><img src="docs/static/img/databases/oceanbase.svg" alt="OceanBase" width="175" height="24" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/oracle" title="Oracle"><img src="docs/static/img/databases/oraclelogo.png" alt="Oracle" width="111" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/presto" title="Presto"><img src="docs/static/img/databases/presto-og.png" alt="Presto" width="127" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/risingwave" title="RisingWave"><img src="docs/static/img/databases/risingwave.svg" alt="RisingWave" width="147" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/sap-hana" title="SAP HANA"><img src="docs/static/img/databases/sap-hana.png" alt="SAP HANA" width="137" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/sap-sybase" title="SAP Sybase"><img src="docs/static/img/databases/sybase.png" alt="SAP Sybase" width="100" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/shillelagh" title="Shillelagh"><img src="docs/static/img/databases/shillelagh.png" alt="Shillelagh" width="40" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/singlestore" title="SingleStore"><img src="docs/static/img/databases/singlestore.png" alt="SingleStore" width="150" height="31" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/snowflake" title="Snowflake"><img src="docs/static/img/databases/snowflake.svg" alt="Snowflake" width="76" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/sqlite" title="SQLite"><img src="docs/static/img/databases/sqlite.png" alt="SQLite" width="84" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/starrocks" title="StarRocks"><img src="docs/static/img/databases/starrocks.png" alt="StarRocks" width="149" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/superset-meta-database" title="Superset meta database"><img src="docs/static/img/databases/superset.svg" alt="Superset meta database" width="150" height="39" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/tdengine" title="TDengine"><img src="docs/static/img/databases/tdengine.png" alt="TDengine" width="140" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/teradata" title="Teradata"><img src="docs/static/img/databases/teradata.png" alt="Teradata" width="124" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/timescaledb" title="TimescaleDB"><img src="docs/static/img/databases/timescale.png" alt="TimescaleDB" width="150" height="36" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/trino" title="Trino"><img src="docs/static/img/databases/trino.png" alt="Trino" width="89" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/vertica" title="Vertica"><img src="docs/static/img/databases/vertica.png" alt="Vertica" width="128" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/ydb" title="YDB"><img src="docs/static/img/databases/ydb.svg" alt="YDB" width="110" height="40" /></a>
|
||||
<a href="https://superset.apache.org/docs/databases/supported/yugabytedb" title="YugabyteDB"><img src="docs/static/img/databases/yugabyte.png" alt="YugabyteDB" width="150" height="26" /></a>
|
||||
<img src="https://superset.apache.org/img/databases/redshift.png" alt="redshift" border="0" width="200"/>
|
||||
<img src="https://superset.apache.org/img/databases/google-biquery.png" alt="google-bigquery" border="0" width="200"/>
|
||||
<img src="https://superset.apache.org/img/databases/snowflake.png" alt="snowflake" border="0" width="200"/>
|
||||
<img src="https://superset.apache.org/img/databases/trino.png" alt="trino" border="0" width="150" />
|
||||
<img src="https://superset.apache.org/img/databases/presto.png" alt="presto" border="0" width="200"/>
|
||||
<img src="https://superset.apache.org/img/databases/databricks.png" alt="databricks" border="0" width="160" />
|
||||
<img src="https://superset.apache.org/img/databases/druid.png" alt="druid" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/firebolt.png" alt="firebolt" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/timescale.png" alt="timescale" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/postgresql.png" alt="postgresql" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/mysql.png" alt="mysql" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/mssql-server.png" alt="mssql-server" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/ibm-db2.svg" alt="db2" border="0" width="220" />
|
||||
<img src="https://superset.apache.org/img/databases/sqlite.png" alt="sqlite" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/sybase.png" alt="sybase" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/mariadb.png" alt="mariadb" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/vertica.png" alt="vertica" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/oracle.png" alt="oracle" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/firebird.png" alt="firebird" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/greenplum.png" alt="greenplum" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/clickhouse.png" alt="clickhouse" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/exasol.png" alt="exasol" border="0" width="160" />
|
||||
<img src="https://superset.apache.org/img/databases/monet-db.png" alt="monet-db" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/apache-kylin.png" alt="apache-kylin" border="0" width="80"/>
|
||||
<img src="https://superset.apache.org/img/databases/hologres.png" alt="hologres" border="0" width="80"/>
|
||||
<img src="https://superset.apache.org/img/databases/netezza.png" alt="netezza" border="0" width="80"/>
|
||||
<img src="https://superset.apache.org/img/databases/pinot.png" alt="pinot" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/teradata.png" alt="teradata" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/yugabyte.png" alt="yugabyte" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/databend.png" alt="databend" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/starrocks.png" alt="starrocks" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/doris.png" alt="doris" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/oceanbase.svg" alt="oceanbase" border="0" width="220" />
|
||||
<img src="https://superset.apache.org/img/databases/sap-hana.png" alt="sap-hana" border="0" width="220" />
|
||||
<img src="https://superset.apache.org/img/databases/denodo.png" alt="denodo" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/ydb.svg" alt="ydb" border="0" width="200" />
|
||||
<img src="https://superset.apache.org/img/databases/tdengine.png" alt="TDengine" border="0" width="200" />
|
||||
</p>
|
||||
<!-- SUPPORTED_DATABASES_END -->
|
||||
|
||||
**A more comprehensive list of supported databases** along with the configuration instructions can be found [here](https://superset.apache.org/docs/databases).
|
||||
**A more comprehensive list of supported databases** along with the configuration instructions can be found [here](https://superset.apache.org/docs/configuration/databases).
|
||||
|
||||
Want to add support for your datastore or data engine? Read more [here](https://superset.apache.org/docs/frequently-asked-questions#does-superset-work-with-insert-database-engine-here) about the technical requirements.
|
||||
|
||||
@@ -189,25 +155,20 @@ Try out Superset's [quickstart](https://superset.apache.org/docs/quickstart/) gu
|
||||
- [Join our community's Slack](http://bit.ly/join-superset-slack)
|
||||
and please read our [Slack Community Guidelines](https://github.com/apache/superset/blob/master/CODE_OF_CONDUCT.md#slack-community-guidelines)
|
||||
- [Join our dev@superset.apache.org Mailing list](https://lists.apache.org/list.html?dev@superset.apache.org). To join, simply send an email to [dev-subscribe@superset.apache.org](mailto:dev-subscribe@superset.apache.org)
|
||||
- Follow us on social media:
|
||||
[X](https://x.com/apachesuperset) |
|
||||
[LinkedIn](https://www.linkedin.com/company/apache-superset) |
|
||||
[Bluesky](https://bsky.app/profile/apachesuperset.bsky.social) |
|
||||
[Reddit](https://reddit.com/r/apache-superset)
|
||||
- If you want to help troubleshoot GitHub Issues involving the numerous database drivers that Superset supports, please consider adding your name and the databases you have access to on the [Superset Database Familiarity Rolodex](https://docs.google.com/spreadsheets/d/1U1qxiLvOX0kBTUGME1AHHi6Ywel6ECF8xk_Qy-V9R8c/edit#gid=0)
|
||||
- Join Superset's Town Hall and [Operational Model](https://preset.io/blog/the-superset-operational-model-wants-you/) recurring meetings. Meeting info is available on the [Superset Community Calendar](https://superset.apache.org/community)
|
||||
|
||||
## Contributor Guide
|
||||
|
||||
Interested in contributing? Check out our
|
||||
[Developer Guide](https://superset.apache.org/developer-docs/)
|
||||
[CONTRIBUTING.md](https://github.com/apache/superset/blob/master/CONTRIBUTING.md)
|
||||
to find resources around contributing along with a detailed guide on
|
||||
how to set up a development environment.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Superset "In the Wild"](https://superset.apache.org/inTheWild) - see who's using Superset, and [add your organization](https://github.com/apache/superset/edit/master/RESOURCES/INTHEWILD.yaml) to the list!
|
||||
- [Feature Flags](https://superset.apache.org/docs/configuration/feature-flags) - the status of Superset's Feature Flags.
|
||||
- [Superset "In the Wild"](https://github.com/apache/superset/blob/master/RESOURCES/INTHEWILD.md) - open a PR to add your org to the list!
|
||||
- [Feature Flags](https://github.com/apache/superset/blob/master/RESOURCES/FEATURE_FLAGS.md) - the status of Superset's Feature Flags.
|
||||
- [Standard Roles](https://github.com/apache/superset/blob/master/RESOURCES/STANDARD_ROLES.md) - How RBAC permissions map to roles.
|
||||
- [Superset Wiki](https://github.com/apache/superset/wiki) - Tons of additional community resources: best practices, community content and other information.
|
||||
- [Superset SIPs](https://github.com/orgs/apache/projects/170) - The status of Superset's SIPs (Superset Improvement Proposals) for both consensus and implementation status.
|
||||
|
||||
@@ -458,7 +458,7 @@ cd ../
|
||||
sed -i '' "s/version_string = .*/version_string = \"$SUPERSET_VERSION\"/" setup.py
|
||||
|
||||
# build the python distribution
|
||||
python -m build
|
||||
python setup.py sdist
|
||||
```
|
||||
|
||||
Publish to PyPI
|
||||
|
||||
@@ -92,7 +92,7 @@ Some of the new features in this release are disabled by default. Each has a fea
|
||||
|
||||
| Feature | Feature Flag | Dependencies | Documentation
|
||||
| --- | --- | --- | --- |
|
||||
| Global Async Queries | `GLOBAL_ASYNC_QUERIES: True` | Redis 5.0+, celery workers configured and running | [Extra documentation](https://superset.apache.org/docs/contributing/misc#async-chart-queries)
|
||||
| Global Async Queries | `GLOBAL_ASYNC_QUERIES: True` | Redis 5.0+, celery workers configured and running | [Extra documentation](https://github.com/apache/superset/blob/master/CONTRIBUTING.md#async-chart-queries )
|
||||
| Dashboard Native Filters | `DASHBOARD_NATIVE_FILTERS: True` | |
|
||||
| Alerts & Reporting | `ALERT_REPORTS: True` | [Celery workers configured & celery beat process](https://superset.apache.org/docs/installation/async-queries-celery) |
|
||||
| Homescreen Thumbnails | `THUMBNAILS: TRUE, THUMBNAIL_CACHE_CONFIG: CacheConfig = { "CACHE_TYPE": "null", "CACHE_NO_NULL_WARNING": True}`| selenium, pillow 7, celery |
|
||||
|
||||
@@ -56,33 +56,8 @@ def verify_sha512(filename: str) -> str:
|
||||
# Part 2: Verify RSA key - this is the same as running `gpg --verify {release}.asc {release}` and comparing the RSA key and email address against the KEYS file # noqa: E501
|
||||
|
||||
|
||||
KEYS_URL = "https://downloads.apache.org/superset/KEYS"
|
||||
|
||||
|
||||
def ensure_keys_imported() -> None:
|
||||
"""Import the Apache Superset KEYS file into the local GPG keyring.
|
||||
|
||||
Without this, `gpg --verify` returns "No public key" and the signature
|
||||
cannot actually be verified — only the key ID in the signature metadata
|
||||
is visible.
|
||||
"""
|
||||
try:
|
||||
keys = requests.get(KEYS_URL, timeout=30)
|
||||
except requests.RequestException as exc:
|
||||
print(f"Warning: could not fetch KEYS file for import: {exc}")
|
||||
return
|
||||
if keys.status_code != 200:
|
||||
print(f"Warning: could not fetch KEYS file (HTTP {keys.status_code})")
|
||||
return
|
||||
subprocess.run( # noqa: S603
|
||||
["gpg", "--import"], # noqa: S607
|
||||
input=keys.content,
|
||||
capture_output=True,
|
||||
)
|
||||
|
||||
|
||||
def get_gpg_info(filename: str) -> tuple[Optional[str], Optional[str]]:
|
||||
"""Run the GPG verify command and extract RSA/EDDSA key and email address."""
|
||||
"""Run the GPG verify command and extract RSA key and email address."""
|
||||
asc_filename = filename + ".asc"
|
||||
result = subprocess.run( # noqa: S603
|
||||
["gpg", "--verify", asc_filename, filename], # noqa: S607
|
||||
@@ -90,50 +65,25 @@ def get_gpg_info(filename: str) -> tuple[Optional[str], Optional[str]]:
|
||||
)
|
||||
output = result.stderr.decode()
|
||||
|
||||
# If no public key was available, import KEYS and retry so that
|
||||
# `Good signature from "Name <email>"` appears in the output.
|
||||
if "No public key" in output:
|
||||
ensure_keys_imported()
|
||||
result = subprocess.run( # noqa: S603
|
||||
["gpg", "--verify", asc_filename, filename], # noqa: S607
|
||||
capture_output=True, # noqa: S607
|
||||
)
|
||||
output = result.stderr.decode()
|
||||
|
||||
rsa_key = re.search(r"RSA key ([0-9A-F]+)", output)
|
||||
eddsa_key = re.search(r"EDDSA key ([0-9A-F]+)", output)
|
||||
|
||||
# Try multiple patterns — `Good signature from` is the most reliable
|
||||
# source of the email; `issuer` is a fallback for older gpg output.
|
||||
email_patterns = (
|
||||
r'Good signature from ".*?<([^>]+)>"',
|
||||
r'aka ".*?<([^>]+)>"',
|
||||
r'issuer "([^"]+)"',
|
||||
)
|
||||
email_result: Optional[str] = None
|
||||
for pattern in email_patterns:
|
||||
match = re.search(pattern, output)
|
||||
if match:
|
||||
email_result = match.group(1)
|
||||
break
|
||||
email = re.search(r'issuer "([^"]+)"', output)
|
||||
|
||||
rsa_key_result = rsa_key.group(1) if rsa_key else None
|
||||
eddsa_key_result = eddsa_key.group(1) if eddsa_key else None
|
||||
email_result = email.group(1) if email else None
|
||||
|
||||
key_result = rsa_key_result or eddsa_key_result
|
||||
|
||||
# Debugging:
|
||||
if key_result:
|
||||
print("RSA or EDDSA Key found")
|
||||
else:
|
||||
print("Warning: No RSA or EDDSA key found in GPG verification output.")
|
||||
if email_result:
|
||||
print(f"Email found: {email_result}")
|
||||
print("email found")
|
||||
else:
|
||||
print("Warning: No email address found in GPG verification output.")
|
||||
if "No public key" in output:
|
||||
print(
|
||||
"Hint: public key is not in your keyring. Import it with:\n"
|
||||
f" curl -s {KEYS_URL} | gpg --import"
|
||||
)
|
||||
|
||||
return key_result, email_result
|
||||
|
||||
|
||||
103
RESOURCES/FEATURE_FLAGS.md
Normal file
103
RESOURCES/FEATURE_FLAGS.md
Normal file
@@ -0,0 +1,103 @@
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
# Superset Feature Flags
|
||||
|
||||
This is a list of the current Superset optional features. See config.py for default values. These features can be turned on/off by setting your preferred values in superset_config.py to True/False respectively
|
||||
|
||||
## In Development
|
||||
|
||||
These features are considered **unfinished** and should only be used on development environments.
|
||||
|
||||
[//]: # "PLEASE KEEP THE LIST SORTED ALPHABETICALLY"
|
||||
|
||||
- ALERT_REPORT_TABS
|
||||
- DATE_RANGE_TIMESHIFTS_ENABLED
|
||||
- ENABLE_ADVANCED_DATA_TYPES
|
||||
- PRESTO_EXPAND_DATA
|
||||
- SHARE_QUERIES_VIA_KV_STORE
|
||||
- TAGGING_SYSTEM
|
||||
- CHART_PLUGINS_EXPERIMENTAL
|
||||
|
||||
## In Testing
|
||||
|
||||
These features are **finished** but currently being tested. They are usable, but may still contain some bugs.
|
||||
|
||||
[//]: # "PLEASE KEEP THE LIST SORTED ALPHABETICALLY"
|
||||
|
||||
- ALERT_REPORTS: [(docs)](https://superset.apache.org/docs/configuration/alerts-reports)
|
||||
- ALLOW_FULL_CSV_EXPORT
|
||||
- CACHE_IMPERSONATION
|
||||
- CONFIRM_DASHBOARD_DIFF
|
||||
- DYNAMIC_PLUGINS
|
||||
- DATE_FORMAT_IN_EMAIL_SUBJECT: [(docs)](https://superset.apache.org/docs/configuration/alerts-reports#commons)
|
||||
- ENABLE_SUPERSET_META_DB: [(docs)](https://superset.apache.org/docs/configuration/databases/#querying-across-databases)
|
||||
- ESTIMATE_QUERY_COST
|
||||
- GLOBAL_ASYNC_QUERIES [(docs)](https://github.com/apache/superset/blob/master/CONTRIBUTING.md#async-chart-queries)
|
||||
- IMPERSONATE_WITH_EMAIL_PREFIX
|
||||
- PLAYWRIGHT_REPORTS_AND_THUMBNAILS
|
||||
- RLS_IN_SQLLAB
|
||||
- SSH_TUNNELING [(docs)](https://superset.apache.org/docs/configuration/setup-ssh-tunneling)
|
||||
- USE_ANALAGOUS_COLORS
|
||||
|
||||
## Stable
|
||||
|
||||
These features flags are **safe for production**. They have been tested and will be supported for the at least the current major version cycle.
|
||||
|
||||
[//]: # "PLEASE KEEP THESE LISTS SORTED ALPHABETICALLY"
|
||||
|
||||
### Flags on the path to feature launch and flag deprecation/removal
|
||||
|
||||
- DASHBOARD_VIRTUALIZATION
|
||||
|
||||
### Flags retained for runtime configuration
|
||||
|
||||
Currently some of our feature flags act as dynamic configurations that can changed
|
||||
on the fly. This acts in contradiction with the typical ephemeral feature flag use case,
|
||||
where the flag is used to mature a feature, and eventually deprecated once the feature is
|
||||
solid. Eventually we'll likely refactor these under a more formal "dynamic configurations" managed
|
||||
independently. This new framework will also allow for non-boolean configurations.
|
||||
|
||||
- ALERTS_ATTACH_REPORTS
|
||||
- ALLOW_ADHOC_SUBQUERY
|
||||
- DASHBOARD_RBAC [(docs)](https://superset.apache.org/docs/using-superset/creating-your-first-dashboard#manage-access-to-dashboards)
|
||||
- DATAPANEL_CLOSED_BY_DEFAULT
|
||||
- DRILL_BY
|
||||
- DRUID_JOINS
|
||||
- EMBEDDABLE_CHARTS
|
||||
- EMBEDDED_SUPERSET
|
||||
- ENABLE_TEMPLATE_PROCESSING
|
||||
- ESCAPE_MARKDOWN_HTML
|
||||
- LISTVIEWS_DEFAULT_CARD_VIEW
|
||||
- SCHEDULED_QUERIES [(docs)](https://superset.apache.org/docs/configuration/alerts-reports)
|
||||
- SLACK_ENABLE_AVATARS (see `superset/config.py` for more information)
|
||||
- SQLLAB_BACKEND_PERSISTENCE
|
||||
- SQL_VALIDATORS_BY_ENGINE [(docs)](https://superset.apache.org/docs/configuration/sql-templating)
|
||||
- THUMBNAILS [(docs)](https://superset.apache.org/docs/configuration/cache)
|
||||
|
||||
## Deprecated Flags
|
||||
|
||||
These features flags currently default to True and **will be removed in a future major release**. For this current release you can turn them off by setting your config to False, but it is advised to remove or set these flags in your local configuration to **True** so that you do not experience any unexpected changes in a future release.
|
||||
|
||||
[//]: # "PLEASE KEEP THE LIST SORTED ALPHABETICALLY"
|
||||
|
||||
- AVOID_COLORS_COLLISION
|
||||
- DRILL_TO_DETAIL
|
||||
- ENABLE_JAVASCRIPT_CONTROLS
|
||||
- KV_STORE
|
||||
226
RESOURCES/INTHEWILD.md
Normal file
226
RESOURCES/INTHEWILD.md
Normal file
@@ -0,0 +1,226 @@
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
## Superset Users in the Wild
|
||||
|
||||
Here's a list of organizations, broken down into broad industry categories, that have taken the time to send a PR to let
|
||||
the world know they are using Apache Superset. If you are a user and want to be recognized,
|
||||
all you have to do is file a simple PR [like this one](https://github.com/apache/superset/pull/10122) — [just click here](https://github.com/apache/superset/edit/master/RESOURCES/INTHEWILD.md) to do so. If you think
|
||||
the categorization is inaccurate, please file a PR with your correction as well.
|
||||
Join our growing community!
|
||||
|
||||
### Sharing Economy
|
||||
|
||||
- [Airbnb](https://github.com/airbnb)
|
||||
- [Faasos](https://faasos.com/) [@shashanksingh]
|
||||
- [Free2Move](https://www.free2move.com/) [@PaoloTerzi]
|
||||
- [Hostnfly](https://www.hostnfly.com/) [@alexisrosuel]
|
||||
- [Lime](https://www.li.me/) [@cxmcc]
|
||||
- [Lyft](https://www.lyft.com/)
|
||||
- [Ontruck](https://www.ontruck.com/)
|
||||
|
||||
### Financial Services
|
||||
|
||||
- [Aktia Bank plc](https://www.aktia.com)
|
||||
- [American Express](https://www.americanexpress.com) [@TheLastSultan]
|
||||
- [bumper](https://www.bumper.co/) [@vasu-ram, @JamiePercival]
|
||||
- [Cape Crypto](https://capecrypto.com)
|
||||
- [Capital Service S.A.](https://capitalservice.pl) [@pkonarzewski]
|
||||
- [Clark.de](https://clark.de/)
|
||||
- [Europace](https://europace.de)
|
||||
- [KarrotPay](https://www.daangnpay.com/)
|
||||
- [Remita](https://remita.net) [@mujibishola]
|
||||
- [Taveo](https://www.taveo.com) [@codek]
|
||||
- [Unit](https://www.unit.co/about-us) [@amitmiran137]
|
||||
- [Wise](https://wise.com) [@koszti]
|
||||
- [Xendit](https://xendit.co/) [@LieAlbertTriAdrian]
|
||||
- [Cover Genius](https://covergenius.com/)
|
||||
|
||||
### Gaming
|
||||
|
||||
- [Popoko VM Games Studio](https://popoko.live)
|
||||
|
||||
### E-Commerce
|
||||
|
||||
- [AiHello](https://www.aihello.com) [@ganeshkrishnan1]
|
||||
- [Bazaar Technologies](https://www.bazaartech.com) [@umair-abro]
|
||||
- [Dragonpass](https://www.dragonpass.com.cn/) [@zhxjdwh]
|
||||
- [Dropit Shopping](https://www.dropit.shop/) [@dropit-dev]
|
||||
- [Fanatics](https://www.fanatics.com/) [@coderfender]
|
||||
- [Fordeal](https://www.fordeal.com) [@Renkai]
|
||||
- [Fynd](https://www.fynd.com/) [@darpanjain07]
|
||||
- [GFG - Global Fashion Group](https://global-fashion-group.com) [@ksaagariconic]
|
||||
- [GoTo/Gojek](https://www.gojek.io/) [@gwthm-in]
|
||||
- [HuiShouBao](https://www.huishoubao.com/) [@Yukinoshita-Yukino]
|
||||
- [Now](https://www.now.vn/) [@davidkohcw]
|
||||
- [Qunar](https://www.qunar.com/) [@flametest]
|
||||
- [Rakuten Viki](https://www.viki.com)
|
||||
- [Shopee](https://shopee.sg) [@xiaohanyu]
|
||||
- [Shopkick](https://www.shopkick.com) [@LAlbertalli]
|
||||
- [ShopUp](https://www.shopup.org/) [@gwthm-in]
|
||||
- [Tails.com](https://tails.com/gb/) [@alanmcruickshank]
|
||||
- [THE ICONIC](https://theiconic.com.au/) [@ksaagariconic]
|
||||
- [Utair](https://www.utair.ru) [@utair-digital]
|
||||
- [VkusVill](https://vkusvill.ru/) [@ETselikov]
|
||||
- [Zalando](https://www.zalando.com) [@dmigo]
|
||||
- [Zalora](https://www.zalora.com) [@ksaagariconic]
|
||||
- [Zepto](https://www.zeptonow.com/) [@gwthm-in]
|
||||
|
||||
### Enterprise Technology
|
||||
|
||||
- [A3Data](https://a3data.com.br) [@neylsoncrepalde]
|
||||
- [Analytics Aura](https://analyticsaura.com/) [@Analytics-Aura]
|
||||
- [Apollo GraphQL](https://www.apollographql.com/) [@evans]
|
||||
- [Astronomer](https://www.astronomer.io) [@ryw]
|
||||
- [Avesta Technologies](https://avestatechnologies.com/) [@TheRum]
|
||||
- [Caizin](https://caizin.com/) [@tejaskatariya]
|
||||
- [Canonical](https://canonical.com)
|
||||
- [Careem](https://www.careem.com/) [@samraHanif0340]
|
||||
- [Cloudsmith](https://cloudsmith.io) [@alancarson]
|
||||
- [Cyberhaven](https://www.cyberhaven.com/) [@toliver-ch]
|
||||
- [Deepomatic](https://deepomatic.com/) [@Zanoellia]
|
||||
- [Dial Once](https://www.dial-once.com/)
|
||||
- [Dremio](https://dremio.com) [@narendrans]
|
||||
- [EFinance](https://www.efinance.com.eg) [@habeeb556]
|
||||
- [Elestio](https://elest.io/) [@kaiwalyakoparkar]
|
||||
- [ELMO Cloud HR & Payroll](https://elmosoftware.com.au/)
|
||||
- [Endress+Hauser](https://www.endress.com/) [@rumbin]
|
||||
- [FBK - ICT center](https://ict.fbk.eu)
|
||||
- [Formbricks](https://formbricks.com)
|
||||
- [Gavagai](https://gavagai.io) [@gavagai-corp]
|
||||
- [GfK Data Lab](https://www.gfk.com/home) [@mherr]
|
||||
- [HPE](https://www.hpe.com/in/en/home.html) [@anmol-hpe]
|
||||
- [Hydrolix](https://www.hydrolix.io/)
|
||||
- [Intercom](https://www.intercom.com/) [@kate-gallo]
|
||||
- [jampp](https://jampp.com/)
|
||||
- [Konfío](https://konfio.mx) [@uis-rodriguez]
|
||||
- [Mainstrat](https://mainstrat.com/)
|
||||
- [mishmash io](https://mishmash.io/) [@mishmash-io]
|
||||
- [Myra Labs](https://www.myralabs.com/) [@viksit]
|
||||
- [Nielsen](https://www.nielsen.com/) [@amitNielsen]
|
||||
- [Ona](https://ona.io) [@pld]
|
||||
- [Orange](https://www.orange.com) [@icsu]
|
||||
- [Oslandia](https://oslandia.com)
|
||||
- [Oxylabs](https://oxylabs.io/) [@rytis-ulys]
|
||||
- [Peak AI](https://www.peak.ai/) [@azhar22k]
|
||||
- [PeopleDoc](https://www.people-doc.com) [@rodo]
|
||||
- [PlaidCloud](https://www.plaidcloud.com)
|
||||
- [Preset, Inc.](https://preset.io)
|
||||
- [PubNub](https://pubnub.com) [@jzucker2]
|
||||
- [ReadyTech](https://www.readytech.io)
|
||||
- [Reward Gateway](https://www.rewardgateway.com)
|
||||
- [RIADVICE](https://riadvice.tn) [@riadvice]
|
||||
- [ScopeAI](https://www.getscopeai.com) [@iloveluce]
|
||||
- [shipmnts](https://shipmnts.com)
|
||||
- [Showmax](https://showmax.com) [@bobek]
|
||||
- [SingleStore](https://www.singlestore.com/)
|
||||
- [TechAudit](https://www.techaudit.info) [@ETselikov]
|
||||
- [Tenable](https://www.tenable.com) [@dflionis]
|
||||
- [Tentacle](https://www.linkedin.com/company/tentacle-cmi/) [@jdclarke5]
|
||||
- [timbr.ai](https://timbr.ai/) [@semantiDan]
|
||||
- [Tobii](https://www.tobii.com/) [@dwa]
|
||||
- [Tooploox](https://www.tooploox.com/) [@jakubczaplicki]
|
||||
- [Unvired](https://unvired.com) [@srinisubramanian]
|
||||
- [Virtuoso QA](https://www.virtuosoqa.com)
|
||||
- [Whale](https://whale.im)
|
||||
- [Windsor.ai](https://www.windsor.ai/) [@octaviancorlade]
|
||||
- [WinWin Network马上赢](https://brandct.cn/) [@wenbinye]
|
||||
- [Zeta](https://www.zeta.tech/) [@shaikidris]
|
||||
|
||||
### Media & Entertainment
|
||||
|
||||
- [6play](https://www.6play.fr) [@CoryChaplin]
|
||||
- [bilibili](https://www.bilibili.com) [@Moinheart]
|
||||
- [BurdaForward](https://www.burda-forward.de/en/)
|
||||
- [Douban](https://www.douban.com/) [@luchuan]
|
||||
- [Kuaishou](https://www.kuaishou.com/) [@zhaoyu89730105]
|
||||
- [Netflix](https://www.netflix.com/)
|
||||
- [Prensa Iberica](https://www.prensaiberica.es/) [@zamar-roura]
|
||||
- [TME QQMUSIC/WESING](https://www.tencentmusic.com/) [@shenyuanli,@marklaw]
|
||||
- [Xite](https://xite.com/) [@shashankkoppar]
|
||||
- [Zaihang](https://www.zaih.com/)
|
||||
|
||||
### Education
|
||||
|
||||
- [Aveti Learning](https://avetilearning.com/) [@TheShubhendra]
|
||||
- [Brilliant.org](https://brilliant.org/)
|
||||
- [Open edX](https://openedx.org/)
|
||||
- [Platzi.com](https://platzi.com/)
|
||||
- [Sunbird](https://www.sunbird.org/) [@eksteporg]
|
||||
- [The GRAPH Network](https://thegraphnetwork.org/) [@fccoelho]
|
||||
- [Udemy](https://www.udemy.com/) [@sungjuly]
|
||||
- [VIPKID](https://www.vipkid.com.cn/) [@illpanda]
|
||||
- [WikiMedia Foundation](https://wikimediafoundation.org) [@vg]
|
||||
|
||||
### Energy
|
||||
|
||||
- [Airboxlab](https://foobot.io) [@antoine-galataud]
|
||||
- [DouroECI](https://www.douroeci.com/) [@nunohelibeires]
|
||||
- [Safaricom](https://www.safaricom.co.ke/) [@mmutiso]
|
||||
- [Scoot](https://scoot.co/) [@haaspt]
|
||||
- [Wattbewerb](https://wattbewerb.de/) [@wattbewerb]
|
||||
|
||||
### Healthcare
|
||||
|
||||
- [Amino](https://amino.com) [@shkr]
|
||||
- [Bluesquare](https://www.bluesquarehub.com/) [@madewulf]
|
||||
- [Care](https://www.getcare.io/) [@alandao2021]
|
||||
- [Living Goods](https://www.livinggoods.org) [@chelule]
|
||||
- [Maieutical Labs](https://maieuticallabs.it) [@xrmx]
|
||||
- [Medic](https://medic.org) [@1yuv]
|
||||
- [REDCap Cloud](https://www.redcapcloud.com/)
|
||||
- [TrustMedis](https://trustmedis.com/) [@famasya]
|
||||
- [WeSure](https://www.wesure.cn/)
|
||||
- [2070Health](https://2070health.com/)
|
||||
|
||||
### HR / Staffing
|
||||
|
||||
- [Swile](https://www.swile.co/) [@PaoloTerzi]
|
||||
- [Symmetrics](https://www.symmetrics.fyi)
|
||||
- [bluquist](https://bluquist.com/)
|
||||
|
||||
### Government
|
||||
|
||||
- [City of Ann Arbor, MI](https://www.a2gov.org/) [@sfirke]
|
||||
- [RIS3 Strategy of CZ, MIT CR](https://www.ris3.cz/) [@RIS3CZ]
|
||||
- [NRLM - Sarathi, India](https://pib.gov.in/PressReleasePage.aspx?PRID=1999586)
|
||||
|
||||
### Travel
|
||||
|
||||
- [Agoda](https://www.agoda.com/) [@lostseaway, @maiake, @obombayo]
|
||||
- [HomeToGo](https://hometogo.com/) [@pedromartinsteenstrup]
|
||||
- [Skyscanner](https://www.skyscanner.net/) [@cleslie, @stanhoucke]
|
||||
|
||||
### Others
|
||||
|
||||
- [10Web](https://10web.io/)
|
||||
- [AI inside](https://inside.ai/en/)
|
||||
- [Automattic](https://automattic.com/) [@Khrol, @Usiel]
|
||||
- [Dropbox](https://www.dropbox.com/) [@bkyryliuk]
|
||||
- [Flowbird](https://flowbird.com) [@EmmanuelCbd]
|
||||
- [GEOTAB](https://www.geotab.com) [@JZ6]
|
||||
- [Grassroot](https://www.grassrootinstitute.org/)
|
||||
- [Increff](https://www.increff.com/) [@ishansinghania]
|
||||
- [komoot](https://www.komoot.com/) [@christophlingg]
|
||||
- [Let's Roam](https://www.letsroam.com/)
|
||||
- [Machrent SA](https://www.machrent.com/)
|
||||
- [Onebeat](https://1beat.com/) [@GuyAttia]
|
||||
- [X](https://x.com/)
|
||||
- [VLMedia](https://www.vlmedia.com.tr/) [@ibotheperfect]
|
||||
- [Yahoo!](https://yahoo.com/)
|
||||
@@ -1,703 +0,0 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# Apache Superset Users in the Wild
|
||||
#
|
||||
# To add your organization:
|
||||
# 1. Find the appropriate category (or add a new one)
|
||||
# 2. Add an entry with your organization details
|
||||
# 3. Optionally add a logo file to docs/static/img/logos/
|
||||
#
|
||||
# Required fields:
|
||||
# - name: Your organization name
|
||||
# - url: Link to your organization's website
|
||||
#
|
||||
# Optional fields:
|
||||
# - logo: Filename of logo in docs/static/img/logos/ (e.g., "mycompany.svg")
|
||||
# - contributors: List of GitHub usernames who contributed (e.g., ["@username"])
|
||||
|
||||
categories:
|
||||
Sharing Economy:
|
||||
- name: Airbnb
|
||||
url: https://github.com/airbnb
|
||||
|
||||
- name: Faasos
|
||||
url: https://faasos.com/
|
||||
contributors: ["@shashanksingh"]
|
||||
|
||||
- name: Free2Move
|
||||
url: https://www.free2move.com/
|
||||
contributors: ["@PaoloTerzi"]
|
||||
|
||||
- name: Hostnfly
|
||||
url: https://www.hostnfly.com/
|
||||
contributors: ["@alexisrosuel"]
|
||||
|
||||
- name: Lime
|
||||
url: https://www.li.me/
|
||||
contributors: ["@cxmcc"]
|
||||
|
||||
- name: Lyft
|
||||
url: https://www.lyft.com/
|
||||
|
||||
- name: Ontruck
|
||||
url: https://www.ontruck.com/
|
||||
|
||||
Financial Services:
|
||||
- name: Aadhar Housing Finance Limited
|
||||
url: https://www.aadharhousing.com
|
||||
contributors: ["@thakerhardiks"]
|
||||
|
||||
- name: Aktia Bank plc
|
||||
url: https://www.aktia.com
|
||||
|
||||
- name: American Express
|
||||
url: https://www.americanexpress.com
|
||||
contributors: ["@TheLastSultan"]
|
||||
|
||||
- name: bumper
|
||||
url: https://www.bumper.co/
|
||||
contributors: ["@vasu-ram", "@JamiePercival"]
|
||||
|
||||
- name: Cape Crypto
|
||||
url: https://capecrypto.com
|
||||
|
||||
- name: Capital Service S.A.
|
||||
url: https://capitalservice.pl
|
||||
contributors: ["@pkonarzewski"]
|
||||
|
||||
- name: Clark.de
|
||||
url: https://clark.de/
|
||||
|
||||
- name: EnquiryLabs
|
||||
url: https://www.enquirylabs.co.uk
|
||||
|
||||
- name: Europace
|
||||
url: https://europace.de
|
||||
|
||||
- name: KarrotPay
|
||||
url: https://www.daangnpay.com/
|
||||
|
||||
- name: Remita
|
||||
url: https://remita.net
|
||||
contributors: ["@mujibishola"]
|
||||
|
||||
- name: Taveo
|
||||
url: https://www.taveo.com
|
||||
contributors: ["@codek"]
|
||||
|
||||
- name: Unit
|
||||
url: https://www.unit.co/about-us
|
||||
contributors: ["@amitmiran137"]
|
||||
|
||||
- name: Wise
|
||||
url: https://wise.com
|
||||
contributors: ["@koszti"]
|
||||
|
||||
- name: Xendit
|
||||
url: https://xendit.co/
|
||||
contributors: ["@LieAlbertTriAdrian"]
|
||||
|
||||
- name: Cover Genius
|
||||
url: https://covergenius.com/
|
||||
|
||||
Gaming:
|
||||
- name: Popoko VM Games Studio
|
||||
url: https://popoko.live
|
||||
|
||||
E-Commerce:
|
||||
- name: AiHello
|
||||
url: https://www.aihello.com
|
||||
contributors: ["@ganeshkrishnan1"]
|
||||
|
||||
- name: Bazaar Technologies
|
||||
url: https://www.bazaartech.com
|
||||
contributors: ["@umair-abro"]
|
||||
|
||||
- name: Blinkit
|
||||
url: https://www.blinkit.com/
|
||||
contributors: ["@amsharm2"]
|
||||
|
||||
- name: Dragonpass
|
||||
url: https://www.dragonpass.com.cn/
|
||||
contributors: ["@zhxjdwh"]
|
||||
|
||||
- name: Dropit Shopping
|
||||
url: https://www.dropit.shop/
|
||||
contributors: ["@dropit-dev"]
|
||||
|
||||
- name: Fordeal
|
||||
url: https://www.fordeal.com
|
||||
contributors: ["@Renkai"]
|
||||
|
||||
- name: Fynd
|
||||
url: https://www.fynd.com/
|
||||
contributors: ["@darpanjain07"]
|
||||
|
||||
- name: GFG - Global Fashion Group
|
||||
url: https://global-fashion-group.com
|
||||
contributors: ["@ksaagariconic"]
|
||||
|
||||
- name: GoTo/Gojek
|
||||
url: https://www.gojek.io/
|
||||
contributors: ["@gwthm-in"]
|
||||
|
||||
- name: HuiShouBao
|
||||
url: https://www.huishoubao.com/
|
||||
contributors: ["@Yukinoshita-Yukino"]
|
||||
|
||||
- name: Now
|
||||
url: https://www.now.vn/
|
||||
contributors: ["@davidkohcw"]
|
||||
|
||||
- name: Qunar
|
||||
url: https://www.qunar.com/
|
||||
contributors: ["@flametest"]
|
||||
|
||||
- name: Rakuten Viki
|
||||
url: https://www.viki.com
|
||||
|
||||
- name: Shopee
|
||||
url: https://shopee.sg
|
||||
contributors: ["@xiaohanyu"]
|
||||
|
||||
- name: Shopkick
|
||||
url: https://www.shopkick.com
|
||||
contributors: ["@LAlbertalli"]
|
||||
|
||||
- name: ShopUp
|
||||
url: https://www.shopup.org/
|
||||
contributors: ["@gwthm-in"]
|
||||
|
||||
- name: Tails.com
|
||||
url: https://tails.com/gb/
|
||||
contributors: ["@alanmcruickshank"]
|
||||
|
||||
- name: THE ICONIC
|
||||
url: https://theiconic.com.au/
|
||||
contributors: ["@ksaagariconic"]
|
||||
|
||||
- name: Utair
|
||||
url: https://www.utair.ru
|
||||
contributors: ["@utair-digital"]
|
||||
|
||||
- name: VkusVill
|
||||
url: https://vkusvill.ru/
|
||||
contributors: ["@ETselikov"]
|
||||
|
||||
- name: Zalando
|
||||
url: https://www.zalando.com
|
||||
contributors: ["@dmigo"]
|
||||
|
||||
- name: Zalora
|
||||
url: https://www.zalora.com
|
||||
contributors: ["@ksaagariconic"]
|
||||
|
||||
- name: Zepto
|
||||
url: https://www.zeptonow.com/
|
||||
contributors: ["@gwthm-in"]
|
||||
|
||||
Enterprise Technology:
|
||||
- name: A3Data
|
||||
url: https://a3data.com.br
|
||||
contributors: ["@neylsoncrepalde"]
|
||||
|
||||
- name: Analytics Aura
|
||||
url: https://analyticsaura.com/
|
||||
contributors: ["@Analytics-Aura"]
|
||||
|
||||
- name: Apollo GraphQL
|
||||
url: https://www.apollographql.com/
|
||||
contributors: ["@evans"]
|
||||
|
||||
- name: Astronomer
|
||||
url: https://www.astronomer.io
|
||||
contributors: ["@ryw"]
|
||||
|
||||
- name: Avesta Technologies
|
||||
url: https://avestatechnologies.com/
|
||||
contributors: ["@TheRum"]
|
||||
|
||||
- name: Caizin
|
||||
url: https://caizin.com/
|
||||
contributors: ["@tejaskatariya"]
|
||||
|
||||
- name: Canonical
|
||||
url: https://canonical.com
|
||||
|
||||
- name: Careem
|
||||
url: https://www.careem.com/
|
||||
contributors: ["@samraHanif0340"]
|
||||
|
||||
- name: Cloudsmith
|
||||
url: https://cloudsmith.io
|
||||
contributors: ["@alancarson"]
|
||||
|
||||
- name: Cyberhaven
|
||||
url: https://www.cyberhaven.com/
|
||||
contributors: ["@toliver-ch"]
|
||||
|
||||
- name: Deepomatic
|
||||
url: https://deepomatic.com/
|
||||
contributors: ["@Zanoellia"]
|
||||
|
||||
- name: Dial Once
|
||||
url: https://www.dial-once.com/
|
||||
|
||||
- name: Dremio
|
||||
url: https://dremio.com
|
||||
contributors: ["@narendrans"]
|
||||
|
||||
- name: EFinance
|
||||
url: https://www.efinance.com.eg
|
||||
contributors: ["@habeeb556"]
|
||||
|
||||
- name: Elestio
|
||||
url: https://elest.io/
|
||||
contributors: ["@kaiwalyakoparkar"]
|
||||
|
||||
- name: ELMO Cloud HR & Payroll
|
||||
url: https://elmosoftware.com.au/
|
||||
|
||||
- name: Endress+Hauser
|
||||
url: https://www.endress.com/
|
||||
contributors: ["@rumbin"]
|
||||
|
||||
- name: FBK - ICT center
|
||||
url: https://ict.fbk.eu
|
||||
|
||||
- name: Formbricks
|
||||
url: https://formbricks.com
|
||||
|
||||
- name: Gavagai
|
||||
url: https://gavagai.io
|
||||
contributors: ["@gavagai-corp"]
|
||||
|
||||
- name: GfK Data Lab
|
||||
url: https://www.gfk.com/home
|
||||
contributors: ["@mherr"]
|
||||
|
||||
- name: Hifadih Business & Technology
|
||||
url: https://hifadih.net/en
|
||||
logo: hifadih.png
|
||||
contributors: ["@saintLaurent00"]
|
||||
|
||||
# Logo approved by @anmol-hpe on behalf of HPE
|
||||
- name: HPE
|
||||
url: https://www.hpe.com/in/en/home.html
|
||||
logo: hpe.png
|
||||
contributors: ["@anmol-hpe"]
|
||||
|
||||
- name: Hydrolix
|
||||
url: https://www.hydrolix.io/
|
||||
|
||||
- name: Intercom
|
||||
url: https://www.intercom.com/
|
||||
contributors: ["@kate-gallo"]
|
||||
|
||||
- name: jampp
|
||||
url: https://jampp.com/
|
||||
|
||||
- name: Konfío
|
||||
url: https://konfio.mx
|
||||
contributors: ["@uis-rodriguez"]
|
||||
|
||||
- name: Mainstrat
|
||||
url: https://mainstrat.com/
|
||||
|
||||
- name: mishmash io
|
||||
url: https://mishmash.io/
|
||||
contributors: ["@mishmash-io"]
|
||||
|
||||
- name: Myra Labs
|
||||
url: https://www.myralabs.com/
|
||||
contributors: ["@viksit"]
|
||||
|
||||
- name: Nielsen
|
||||
url: https://www.nielsen.com/
|
||||
contributors: ["@amitNielsen"]
|
||||
|
||||
- name: Ona
|
||||
url: https://ona.io
|
||||
contributors: ["@pld"]
|
||||
|
||||
- name: Orange
|
||||
url: https://www.orange.com
|
||||
contributors: ["@icsu"]
|
||||
|
||||
- name: Oslandia
|
||||
url: https://oslandia.com
|
||||
|
||||
- name: Oxylabs
|
||||
url: https://oxylabs.io/
|
||||
contributors: ["@rytis-ulys"]
|
||||
|
||||
- name: Peak AI
|
||||
url: https://www.peak.ai/
|
||||
contributors: ["@azhar22k"]
|
||||
|
||||
- name: PeopleDoc
|
||||
url: https://www.people-doc.com
|
||||
contributors: ["@rodo"]
|
||||
|
||||
- name: PlaidCloud
|
||||
url: https://plaidcloud.com
|
||||
logo: plaidcloud.svg
|
||||
contributors: ["@rad-pat"]
|
||||
|
||||
- name: Preset, Inc.
|
||||
url: https://preset.io
|
||||
logo: preset.svg
|
||||
contributors: ["@mistercrunch", "@betodealmeida", "@dpgaspar", "@rusackas", "@sadpandajoe", "@Vitor-Avila", "@kgabryje", "@geido", "@eschutho", "@Antonio-RiveroMartnez", "@yousoph"]
|
||||
|
||||
- name: PubNub
|
||||
url: https://pubnub.com
|
||||
contributors: ["@jzucker2"]
|
||||
|
||||
- name: ReadyTech
|
||||
url: https://www.readytech.io
|
||||
|
||||
- name: Reward Gateway
|
||||
url: https://www.rewardgateway.com
|
||||
|
||||
- name: RIADVICE
|
||||
url: https://riadvice.tn
|
||||
contributors: ["@riadvice"]
|
||||
|
||||
- name: ScopeAI
|
||||
url: https://www.getscopeai.com
|
||||
contributors: ["@iloveluce"]
|
||||
|
||||
- name: shipmnts
|
||||
url: https://shipmnts.com
|
||||
|
||||
- name: Showmax
|
||||
url: https://showmax.com
|
||||
contributors: ["@bobek"]
|
||||
|
||||
- name: SingleStore
|
||||
url: https://www.singlestore.com/
|
||||
|
||||
- name: TechAudit
|
||||
url: https://www.techaudit.info
|
||||
contributors: ["@ETselikov"]
|
||||
|
||||
- name: Tenable
|
||||
url: https://www.tenable.com
|
||||
contributors: ["@dflionis"]
|
||||
|
||||
- name: Tentacle
|
||||
url: https://www.linkedin.com/company/tentacle-cmi/
|
||||
contributors: ["@jdclarke5"]
|
||||
|
||||
- name: timbr.ai
|
||||
url: https://timbr.ai/
|
||||
contributors: ["@semantiDan"]
|
||||
|
||||
- name: Tobii
|
||||
url: https://www.tobii.com/
|
||||
contributors: ["@dwa"]
|
||||
|
||||
- name: Tooploox
|
||||
url: https://www.tooploox.com/
|
||||
contributors: ["@jakubczaplicki"]
|
||||
|
||||
- name: Unvired
|
||||
url: https://unvired.com
|
||||
contributors: ["@srinisubramanian"]
|
||||
|
||||
- name: UserGuiding
|
||||
url: https://userguiding.com/
|
||||
logo: userguiding.svg
|
||||
contributors: ["@tzercin"]
|
||||
|
||||
- name: Virtuoso QA
|
||||
url: https://www.virtuosoqa.com
|
||||
|
||||
- name: Whale
|
||||
url: https://whale.im
|
||||
|
||||
- name: Windsor.ai
|
||||
url: https://www.windsor.ai/
|
||||
contributors: ["@octaviancorlade"]
|
||||
|
||||
- name: WinWin Network马上赢
|
||||
url: https://brandct.cn/
|
||||
contributors: ["@wenbinye"]
|
||||
|
||||
- name: XNET
|
||||
url: https://xnetmobile.com/
|
||||
logo: xnet.png
|
||||
contributors: ["@deuspt"]
|
||||
|
||||
- name: Zeta
|
||||
url: https://www.zeta.tech/
|
||||
contributors: ["@shaikidris"]
|
||||
|
||||
Media & Entertainment:
|
||||
- name: 6play
|
||||
url: https://www.6play.fr
|
||||
contributors: ["@CoryChaplin"]
|
||||
|
||||
- name: bilibili
|
||||
url: https://www.bilibili.com
|
||||
contributors: ["@Moinheart"]
|
||||
|
||||
- name: BurdaForward
|
||||
url: https://www.burda-forward.de/en/
|
||||
|
||||
- name: Douban
|
||||
url: https://www.douban.com/
|
||||
contributors: ["@luchuan"]
|
||||
|
||||
- name: Kuaishou
|
||||
url: https://www.kuaishou.com/
|
||||
contributors: ["@zhaoyu89730105"]
|
||||
|
||||
- name: Netflix
|
||||
url: https://www.netflix.com/
|
||||
|
||||
- name: Prensa Iberica
|
||||
url: https://www.prensaiberica.es/
|
||||
contributors: ["@zamar-roura"]
|
||||
|
||||
- name: TME QQMUSIC/WESING
|
||||
url: https://www.tencentmusic.com/
|
||||
contributors: ["@shenyuanli", "@marklaw"]
|
||||
|
||||
- name: Xite
|
||||
url: https://xite.com/
|
||||
contributors: ["@shashankkoppar"]
|
||||
|
||||
- name: Zaihang
|
||||
url: https://www.zaih.com/
|
||||
|
||||
Education:
|
||||
- name: Aveti Learning
|
||||
url: https://avetilearning.com/
|
||||
contributors: ["@TheShubhendra"]
|
||||
|
||||
- name: Brilliant.org
|
||||
url: https://brilliant.org/
|
||||
|
||||
- name: Cirrus Assessment
|
||||
url: https://cirrusassessment.com/
|
||||
logo: cirrus.svg
|
||||
contributors: ["@jeroenhabets", "@ddmm-white", "@paulrocost"]
|
||||
|
||||
- name: Open edX
|
||||
url: https://openedx.org/
|
||||
|
||||
- name: Platzi.com
|
||||
url: https://platzi.com/
|
||||
|
||||
- name: Sunbird
|
||||
url: https://www.sunbird.org/
|
||||
contributors: ["@eksteporg"]
|
||||
|
||||
- name: The GRAPH Network
|
||||
url: https://thegraphnetwork.org/
|
||||
contributors: ["@fccoelho"]
|
||||
|
||||
- name: Udemy
|
||||
url: https://www.udemy.com/
|
||||
contributors: ["@sungjuly"]
|
||||
|
||||
- name: VIPKID
|
||||
url: https://www.vipkid.com.cn/
|
||||
contributors: ["@illpanda"]
|
||||
|
||||
- name: WikiMedia Foundation
|
||||
url: https://wikimediafoundation.org
|
||||
contributors: ["@vg"]
|
||||
|
||||
Energy:
|
||||
- name: Airboxlab
|
||||
url: https://foobot.io
|
||||
contributors: ["@antoine-galataud"]
|
||||
|
||||
- name: DouroECI
|
||||
url: https://www.douroeci.com/
|
||||
contributors: ["@nunohelibeires"]
|
||||
|
||||
- name: Safaricom
|
||||
url: https://www.safaricom.co.ke/
|
||||
contributors: ["@mmutiso"]
|
||||
|
||||
- name: Scoot
|
||||
url: https://scoot.co/
|
||||
contributors: ["@haaspt"]
|
||||
|
||||
- name: Wattbewerb
|
||||
url: https://wattbewerb.de/
|
||||
contributors: ["@wattbewerb"]
|
||||
|
||||
- name: Rogow
|
||||
url: https://rogow.com.br/
|
||||
contributors: ["@nilmonto"]
|
||||
|
||||
Healthcare:
|
||||
- name: Amino
|
||||
url: https://amino.com
|
||||
contributors: ["@shkr"]
|
||||
|
||||
- name: Bluesquare
|
||||
url: https://www.bluesquarehub.com/
|
||||
contributors: ["@madewulf"]
|
||||
|
||||
- name: Care
|
||||
url: https://www.getcare.io/
|
||||
contributors: ["@alandao2021"]
|
||||
|
||||
- name: Living Goods
|
||||
url: https://www.livinggoods.org
|
||||
contributors: ["@chelule"]
|
||||
|
||||
- name: Maieutical Labs
|
||||
url: https://maieuticallabs.it
|
||||
contributors: ["@xrmx"]
|
||||
|
||||
- name: Medic
|
||||
url: https://medic.org
|
||||
contributors: ["@1yuv"]
|
||||
|
||||
- name: REDCap Cloud
|
||||
url: https://www.redcapcloud.com/
|
||||
|
||||
- name: TrustMedis
|
||||
url: https://trustmedis.com/
|
||||
contributors: ["@famasya"]
|
||||
|
||||
- name: WeSure
|
||||
url: https://www.wesure.cn/
|
||||
|
||||
- name: 2070Health
|
||||
url: https://2070health.com/
|
||||
|
||||
HR / Staffing:
|
||||
- name: Swile
|
||||
url: https://www.swile.co/
|
||||
contributors: ["@PaoloTerzi"]
|
||||
|
||||
- name: Symmetrics
|
||||
url: https://www.symmetrics.fyi
|
||||
|
||||
- name: bluquist
|
||||
url: https://bluquist.com/
|
||||
|
||||
Government:
|
||||
- name: City of Ann Arbor, MI
|
||||
url: https://www.a2gov.org/
|
||||
contributors: ["@sfirke"]
|
||||
|
||||
- name: RIS3 Strategy of CZ, MIT CR
|
||||
url: https://www.ris3.cz/
|
||||
contributors: ["@RIS3CZ"]
|
||||
|
||||
- name: NRLM - Sarathi, India
|
||||
url: https://pib.gov.in/PressReleasePage.aspx?PRID=1999586
|
||||
|
||||
Mobile Software:
|
||||
- name: VLMedia
|
||||
url: https://www.vlmedia.com.tr
|
||||
logo: vlmedia.svg
|
||||
contributors: ["@iercan"]
|
||||
|
||||
Travel:
|
||||
- name: Agoda
|
||||
url: https://www.agoda.com/
|
||||
contributors: ["@lostseaway", "@maiake", "@obombayo"]
|
||||
|
||||
- name: HomeToGo
|
||||
url: https://hometogo.com/
|
||||
contributors: ["@pedromartinsteenstrup"]
|
||||
|
||||
- name: Skyscanner
|
||||
url: https://www.skyscanner.net/
|
||||
contributors: ["@cleslie", "@stanhoucke"]
|
||||
|
||||
Logistics:
|
||||
- name: Stockarea
|
||||
url: https://stockarea.io
|
||||
|
||||
- name: VTG
|
||||
url: https://www.vtg.de
|
||||
|
||||
Sports:
|
||||
- name: Club 25 de Agosto (Femenino / Women's Team)
|
||||
url: https://www.instagram.com/25deagosto.basketfemenino/
|
||||
contributors: [ "@lion90" ]
|
||||
logo: club25deagosto.svg
|
||||
|
||||
- name: Fanatics
|
||||
url: https://www.fanatics.com/
|
||||
contributors: [ "@coderfender" ]
|
||||
|
||||
- name: komoot
|
||||
url: https://www.komoot.com/
|
||||
contributors: [ "@christophlingg" ]
|
||||
|
||||
Others:
|
||||
- name: 10Web
|
||||
url: https://10web.io/
|
||||
|
||||
- name: AI inside
|
||||
url: https://inside.ai/en/
|
||||
|
||||
- name: Automattic
|
||||
url: https://automattic.com/
|
||||
contributors: ["@Khrol", "@Usiel"]
|
||||
|
||||
- name: Dropbox
|
||||
url: https://www.dropbox.com/
|
||||
contributors: ["@bkyryliuk"]
|
||||
|
||||
- name: Flowbird
|
||||
url: https://flowbird.com
|
||||
contributors: ["@EmmanuelCbd"]
|
||||
|
||||
- name: GEOTAB
|
||||
url: https://www.geotab.com
|
||||
contributors: ["@JZ6"]
|
||||
|
||||
- name: Grassroot
|
||||
url: https://www.grassrootinstitute.org/
|
||||
|
||||
- name: HOLLYLAND猛玛
|
||||
url: https://www.hollyland.com
|
||||
logo: hollyland猛玛.svg
|
||||
contributors: ["@hlyda0601"]
|
||||
|
||||
- name: Increff
|
||||
url: https://www.increff.com/
|
||||
contributors: ["@ishansinghania"]
|
||||
|
||||
- name: Let's Roam
|
||||
url: https://www.letsroam.com/
|
||||
|
||||
- name: Machrent SA
|
||||
url: https://www.machrent.com/
|
||||
|
||||
- name: Onebeat
|
||||
url: https://1beat.com/
|
||||
contributors: ["@GuyAttia"]
|
||||
|
||||
- name: X
|
||||
url: https://x.com/
|
||||
|
||||
- name: Yahoo!
|
||||
url: https://yahoo.com/
|
||||
@@ -17,193 +17,192 @@ specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
| |Admin|Alpha|Gamma|Public|SQL_LAB|
|
||||
|--------------------------------------------------|---|---|---|---|---|
|
||||
| Permission/role description |Admins have all possible rights, including granting or revoking rights from other users and altering other people's slices and dashboards.|Alpha users have access to all data sources, but they cannot grant or revoke access from other users. They are also limited to altering the objects that they own. Alpha users can add and alter data sources.|Gamma users have limited access. They can only consume data coming from data sources they have been given access to through another complementary role. They only have access to view the slices and dashboards made from data sources that they have access to. Currently Gamma users are not able to alter or add data sources. We assume that they are mostly content consumers, though they can create slices and dashboards.|Public is the most restrictive built-in role, designed for anonymous/unauthenticated users viewing public dashboards. It provides minimal read-only access for dashboard viewing with interactive filters. Use `PUBLIC_ROLE_LIKE = "Public"` to apply these permissions to anonymous users.|The sql_lab role grants access to SQL Lab. Note that while Admin users have access to all databases by default, both Alpha and Gamma users need to be given access on a per database basis.||
|
||||
| can read on SavedQuery |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can write on SavedQuery |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can read on CssTemplate |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can write on CssTemplate |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can read on ReportSchedule |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can write on ReportSchedule |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can read on Chart |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can write on Chart |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can read on Annotation |:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|O|
|
||||
| can write on Annotation |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| can read on AnnotationLayerRestApi |:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|O|
|
||||
| can read on Dataset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can write on Dataset |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| can read on Log |:heavy_check_mark:|O|O|O|O|
|
||||
| can write on Log |:heavy_check_mark:|O|O|O|O|
|
||||
| can read on Dashboard |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can write on Dashboard |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can read on Database |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can write on Database |:heavy_check_mark:|O|O|O|O|
|
||||
| can read on Query |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can this form get on ResetPasswordView |:heavy_check_mark:|O|O|O|O|
|
||||
| can this form post on ResetPasswordView |:heavy_check_mark:|O|O|O|O|
|
||||
| can this form get on ResetMyPasswordView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can this form post on ResetMyPasswordView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can this form get on UserInfoEditView |:heavy_check_mark:|O|O|O|O|
|
||||
| can this form post on UserInfoEditView |:heavy_check_mark:|O|O|O|O|
|
||||
| can show on UserDBModelView |:heavy_check_mark:|O|O|O|O|
|
||||
| can edit on UserDBModelView |:heavy_check_mark:|O|O|O|O|
|
||||
| can delete on UserDBModelView |:heavy_check_mark:|O|O|O|O|
|
||||
| can add on UserDBModelView |:heavy_check_mark:|O|O|O|O|
|
||||
| can list on UserDBModelView |:heavy_check_mark:|O|O|O|O|
|
||||
| can userinfo on UserDBModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| resetmypassword on UserDBModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| resetpasswords on UserDBModelView |:heavy_check_mark:|O|O|O|O|
|
||||
| userinfoedit on UserDBModelView |:heavy_check_mark:|O|O|O|O|
|
||||
| can show on RoleModelView |:heavy_check_mark:|O|O|O|O|
|
||||
| can edit on RoleModelView |:heavy_check_mark:|O|O|O|O|
|
||||
| can delete on RoleModelView |:heavy_check_mark:|O|O|O|O|
|
||||
| can add on RoleModelView |:heavy_check_mark:|O|O|O|O|
|
||||
| can list on RoleModelView |:heavy_check_mark:|O|O|O|O|
|
||||
| copyrole on RoleModelView |:heavy_check_mark:|O|O|O|O|
|
||||
| can get on OpenApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can show on SwaggerView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can get on MenuApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can list on AsyncEventsRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can invalidate on CacheRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can csv upload on Database |:heavy_check_mark:|O|O|O|O|
|
||||
| can excel upload on Database |:heavy_check_mark:|O|O|O|O|
|
||||
| can query form data on Api |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can query on Api |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can time range on Api |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can external metadata on Datasource |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can save on Datasource |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| can get on Datasource |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can my queries on SqlLab |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can log on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can import dashboards on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can schemas on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can sqllab history on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can publish on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can csv on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can slice on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can sync druid source on Superset |:heavy_check_mark:|O|O|O|O|
|
||||
| can explore on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can approve on Superset |:heavy_check_mark:|O|O|O|O|
|
||||
| can explore json on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can fetch datasource metadata on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can csrf token on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can sqllab on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can select star on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can warm up cache on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can sqllab table viz on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can available domains on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can request access on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can dashboard on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can post on TableSchemaView |:heavy_check_mark:|O|O|O|:heavy_check_mark:|
|
||||
| can expanded on TableSchemaView |:heavy_check_mark:|O|O|O|:heavy_check_mark:|
|
||||
| can delete on TableSchemaView |:heavy_check_mark:|O|O|O|:heavy_check_mark:|
|
||||
| can get on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can post on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can delete query on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can migrate query on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can activate on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can delete on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can put on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can read on SecurityRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| menu access on Security |:heavy_check_mark:|O|O|O|O|
|
||||
| menu access on List Users |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on List Roles |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Action Log |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Manage |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| menu access on Annotation Layers |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on CSS Templates |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| menu access on Import Dashboards |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Data |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Databases |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Datasets |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Charts |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Dashboards |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on SQL Lab |:heavy_check_mark:|O|O|O|:heavy_check_mark:|
|
||||
| menu access on SQL Editor |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| menu access on Saved Queries |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| menu access on Query Search |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| all datasource access on all_datasource_access |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| all database access on all_database_access |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| all query access on all_query_access |:heavy_check_mark:|O|O|O|O|
|
||||
| can write on DynamicPlugin |:heavy_check_mark:|O|O|O|O|
|
||||
| can edit on DynamicPlugin |:heavy_check_mark:|O|O|O|O|
|
||||
| can list on DynamicPlugin |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can show on DynamicPlugin |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can download on DynamicPlugin |:heavy_check_mark:|O|O|O|O|
|
||||
| can add on DynamicPlugin |:heavy_check_mark:|O|O|O|O|
|
||||
| can delete on DynamicPlugin |:heavy_check_mark:|O|O|O|O|
|
||||
| can external metadata by name on Datasource |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can get value on KV |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can store on KV |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can tagged objects on TagView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can suggestions on TagView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can get on TagView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can post on TagView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can delete on TagView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can edit on DashboardEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can list on DashboardEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can show on DashboardEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can add on DashboardEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can delete on DashboardEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| muldelete on DashboardEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| can edit on SliceEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can list on SliceEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can show on SliceEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can add on SliceEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can delete on SliceEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| muldelete on SliceEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| can edit on AlertModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can list on AlertModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can show on AlertModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can add on AlertModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can delete on AlertModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can list on AlertLogModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can show on AlertLogModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can list on AlertObservationModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can show on AlertObservationModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Row Level Security |:heavy_check_mark:|O|O|O|O|
|
||||
| menu access on Access requests |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Home |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Plugins |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Dashboard Email Schedules |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Chart Emails |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Alerts |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Alerts & Report |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Scan New Datasources |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can share dashboard on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can share chart on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can this form get on ColumnarToDatabaseView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can this form post on ColumnarToDatabaseView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can export on Chart |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can write on DashboardFilterStateRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can read on DashboardFilterStateRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can write on DashboardPermalinkRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can read on DashboardPermalinkRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can delete embedded on Dashboard |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can set embedded on Dashboard |:heavy_check_mark:|O|O|O|O|
|
||||
| can export on Dashboard |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can get embedded on Dashboard |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can export on Database |:heavy_check_mark:|O|O|O|O|
|
||||
| can export on Dataset |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| can write on ExploreFormDataRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can read on ExploreFormDataRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can write on ExplorePermalinkRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can read on ExplorePermalinkRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can export on ImportExportRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can import on ImportExportRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can export on SavedQuery |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|:heavy_check_mark:|
|
||||
| can dashboard permalink on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can grant guest token on SecurityRestApi |:heavy_check_mark:|O|O|O|O|
|
||||
| can read on AdvancedDataType |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can read on EmbeddedDashboard |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can duplicate on Dataset |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| can read on Explore |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can samples on Datasource |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| can read on AvailableDomains |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can get or create dataset on Dataset |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| can get column values on Datasource |:heavy_check_mark:|:heavy_check_mark:|O|O|O|
|
||||
| can export csv on SQLLab |:heavy_check_mark:|O|O|O|:heavy_check_mark:|
|
||||
| can get results on SQLLab |:heavy_check_mark:|O|O|O|:heavy_check_mark:|
|
||||
| can execute sql query on SQLLab |:heavy_check_mark:|O|O|O|:heavy_check_mark:|
|
||||
| can recent activity on Log |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| |Admin|Alpha|Gamma|SQL_LAB|
|
||||
|--------------------------------------------------|---|---|---|---|
|
||||
| Permission/role description |Admins have all possible rights, including granting or revoking rights from other users and altering other people’s slices and dashboards.|Alpha users have access to all data sources, but they cannot grant or revoke access from other users. They are also limited to altering the objects that they own. Alpha users can add and alter data sources.|Gamma users have limited access. They can only consume data coming from data sources they have been given access to through another complementary role. They only have access to view the slices and dashboards made from data sources that they have access to. Currently Gamma users are not able to alter or add data sources. We assume that they are mostly content consumers, though they can create slices and dashboards.|The sql_lab role grants access to SQL Lab. Note that while Admin users have access to all databases by default, both Alpha and Gamma users need to be given access on a per database basis.||
|
||||
| can read on SavedQuery |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can write on SavedQuery |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can read on CssTemplate |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can write on CssTemplate |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can read on ReportSchedule |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can write on ReportSchedule |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can read on Chart |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can write on Chart |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can read on Annotation |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can write on Annotation |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can read on Dataset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can write on Dataset |:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can read on Log |:heavy_check_mark:|O|O|O|
|
||||
| can write on Log |:heavy_check_mark:|O|O|O|
|
||||
| can read on Dashboard |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can write on Dashboard |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can read on Database |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can write on Database |:heavy_check_mark:|O|O|O|
|
||||
| can read on Query |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can this form get on ResetPasswordView |:heavy_check_mark:|O|O|O|
|
||||
| can this form post on ResetPasswordView |:heavy_check_mark:|O|O|O|
|
||||
| can this form get on ResetMyPasswordView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can this form post on ResetMyPasswordView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can this form get on UserInfoEditView |:heavy_check_mark:|O|O|O|
|
||||
| can this form post on UserInfoEditView |:heavy_check_mark:|O|O|O|
|
||||
| can show on UserDBModelView |:heavy_check_mark:|O|O|O|
|
||||
| can edit on UserDBModelView |:heavy_check_mark:|O|O|O|
|
||||
| can delete on UserDBModelView |:heavy_check_mark:|O|O|O|
|
||||
| can add on UserDBModelView |:heavy_check_mark:|O|O|O|
|
||||
| can list on UserDBModelView |:heavy_check_mark:|O|O|O|
|
||||
| can userinfo on UserDBModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| resetmypassword on UserDBModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| resetpasswords on UserDBModelView |:heavy_check_mark:|O|O|O|
|
||||
| userinfoedit on UserDBModelView |:heavy_check_mark:|O|O|O|
|
||||
| can show on RoleModelView |:heavy_check_mark:|O|O|O|
|
||||
| can edit on RoleModelView |:heavy_check_mark:|O|O|O|
|
||||
| can delete on RoleModelView |:heavy_check_mark:|O|O|O|
|
||||
| can add on RoleModelView |:heavy_check_mark:|O|O|O|
|
||||
| can list on RoleModelView |:heavy_check_mark:|O|O|O|
|
||||
| copyrole on RoleModelView |:heavy_check_mark:|O|O|O|
|
||||
| can get on OpenApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can show on SwaggerView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can get on MenuApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can list on AsyncEventsRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can invalidate on CacheRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can csv upload on Database |:heavy_check_mark:|O|O|O|
|
||||
| can excel upload on Database |:heavy_check_mark:|O|O|O|
|
||||
| can query form data on Api |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can query on Api |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can time range on Api |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can external metadata on Datasource |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can save on Datasource |:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can get on Datasource |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can my queries on SqlLab |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can log on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can import dashboards on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can schemas on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can sqllab history on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can publish on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can csv on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can slice on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can sync druid source on Superset |:heavy_check_mark:|O|O|O|
|
||||
| can explore on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can approve on Superset |:heavy_check_mark:|O|O|O|
|
||||
| can explore json on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can fetch datasource metadata on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can csrf token on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can sqllab on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can select star on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can warm up cache on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can sqllab table viz on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can available domains on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can request access on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can dashboard on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can post on TableSchemaView |:heavy_check_mark:|O|O|:heavy_check_mark:|
|
||||
| can expanded on TableSchemaView |:heavy_check_mark:|O|O|:heavy_check_mark:|
|
||||
| can delete on TableSchemaView |:heavy_check_mark:|O|O|:heavy_check_mark:|
|
||||
| can get on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can post on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can delete query on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can migrate query on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can activate on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can delete on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can put on TabStateView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can read on SecurityRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| menu access on Security |:heavy_check_mark:|O|O|O|
|
||||
| menu access on List Users |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on List Roles |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Action Log |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Manage |:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Annotation Layers |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on CSS Templates |:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| menu access on Import Dashboards |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Data |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Databases |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Datasets |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Charts |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Dashboards |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on SQL Lab |:heavy_check_mark:|O|O|:heavy_check_mark:|
|
||||
| menu access on SQL Editor |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| menu access on Saved Queries |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| menu access on Query Search |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| all datasource access on all_datasource_access |:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| all database access on all_database_access |:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| all query access on all_query_access |:heavy_check_mark:|O|O|O|
|
||||
| can write on DynamicPlugin |:heavy_check_mark:|O|O|O|
|
||||
| can edit on DynamicPlugin |:heavy_check_mark:|O|O|O|
|
||||
| can list on DynamicPlugin |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can show on DynamicPlugin |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can download on DynamicPlugin |:heavy_check_mark:|O|O|O|
|
||||
| can add on DynamicPlugin |:heavy_check_mark:|O|O|O|
|
||||
| can delete on DynamicPlugin |:heavy_check_mark:|O|O|O|
|
||||
| can external metadata by name on Datasource |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can get value on KV |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can store on KV |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can tagged objects on TagView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can suggestions on TagView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can get on TagView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can post on TagView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can delete on TagView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can edit on DashboardEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can list on DashboardEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can show on DashboardEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can add on DashboardEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can delete on DashboardEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| muldelete on DashboardEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can edit on SliceEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can list on SliceEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can show on SliceEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can add on SliceEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can delete on SliceEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| muldelete on SliceEmailScheduleView |:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can edit on AlertModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can list on AlertModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can show on AlertModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can add on AlertModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can delete on AlertModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can list on AlertLogModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can show on AlertLogModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can list on AlertObservationModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can show on AlertObservationModelView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Row Level Security |:heavy_check_mark:|O|O|O|
|
||||
| menu access on Access requests |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Home |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Plugins |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Dashboard Email Schedules |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Chart Emails |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Alerts |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Alerts & Report |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| menu access on Scan New Datasources |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can share dashboard on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can share chart on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can this form get on ColumnarToDatabaseView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can this form post on ColumnarToDatabaseView |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can export on Chart |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can write on DashboardFilterStateRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can read on DashboardFilterStateRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can write on DashboardPermalinkRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can read on DashboardPermalinkRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can delete embedded on Dashboard |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can set embedded on Dashboard |:heavy_check_mark:|O|O|O|
|
||||
| can export on Dashboard |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can get embedded on Dashboard |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can export on Database |:heavy_check_mark:|O|O|O|
|
||||
| can export on Dataset |:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can write on ExploreFormDataRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can read on ExploreFormDataRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can write on ExplorePermalinkRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can read on ExplorePermalinkRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can export on ImportExportRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can import on ImportExportRestApi |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can export on SavedQuery |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|
|
||||
| can dashboard permalink on Superset |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can grant guest token on SecurityRestApi |:heavy_check_mark:|O|O|O|
|
||||
| can read on AdvancedDataType |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can read on EmbeddedDashboard |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can duplicate on Dataset |:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can read on Explore |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can samples on Datasource |:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can read on AvailableDomains |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
| can get or create dataset on Dataset |:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can get column values on Datasource |:heavy_check_mark:|:heavy_check_mark:|O|O|
|
||||
| can export csv on SQLLab |:heavy_check_mark:|O|O|:heavy_check_mark:|
|
||||
| can get results on SQLLab |:heavy_check_mark:|O|O|:heavy_check_mark:|
|
||||
| can execute sql query on SQLLab |:heavy_check_mark:|O|O|:heavy_check_mark:|
|
||||
| can recent activity on Log |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:|O|
|
||||
|
||||
145
SECURITY.md
145
SECURITY.md
@@ -1,145 +0,0 @@
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
# Security Policy
|
||||
|
||||
This is a project of the [Apache Software Foundation](https://apache.org) and follows the
|
||||
ASF [vulnerability handling process](https://apache.org/security/#vulnerability-handling).
|
||||
|
||||
## Reporting Vulnerabilities
|
||||
|
||||
**⚠️ Please do not file GitHub issues for security vulnerabilities as they are public! ⚠️**
|
||||
|
||||
|
||||
Apache Software Foundation takes a rigorous standpoint in resolving the security issues
|
||||
in its software projects. Apache Superset is highly sensitive and forthcoming to issues
|
||||
pertaining to its features and functionality.
|
||||
If you have any concern or believe you have found a vulnerability in Apache Superset,
|
||||
please get in touch with the Apache Superset Security Team privately at
|
||||
e-mail address [security@superset.apache.org](mailto:security@superset.apache.org).
|
||||
|
||||
More details can be found on the ASF website at
|
||||
[ASF vulnerability reporting process](https://apache.org/security/#reporting-a-vulnerability)
|
||||
|
||||
**Submission Standards & AI Policy**
|
||||
|
||||
To ensure engineering focus remains on verified risks and to manage high reporting volumes, all reports must meet the following criteria:
|
||||
- Plain Text Format: In accordance with Apache guidelines, please provide all details in plain text within the email body. Avoid sending PDFs, Word documents, or password-protected archives.
|
||||
- Mandatory AI Disclosure: If you utilized Large Language Models (LLMs) or AI tools to identify a flaw or assist in writing a report, you must disclose this in your submission so our triage team can contextualize the findings.
|
||||
- Human-Verified PoC: All submissions must include a manual, step-by-step Proof of Concept (PoC) performed on a supported release. Raw AI outputs, hypothetical chat transcripts, or unverified scanner logs will be closed as Invalid.
|
||||
|
||||
We kindly ask you to include the following information in your report to assist our developers in triaging and remediating issues efficiently:
|
||||
- Version/Commit: The specific version of Apache Superset or the Git commit hash you are using.
|
||||
- Configuration: A sanitized copy of your `superset_config.py` file or any config overrides.
|
||||
- Environment: Your deployment method (e.g., Docker Compose, Helm, or source) and relevant OS/Browser details.
|
||||
- Impacted Component: Identification of the affected area (e.g., Python backend, React frontend, or a specific database connector).
|
||||
- Expected vs. Actual Behavior: A clear description of the intended system behavior versus the observed vulnerability.
|
||||
- Detailed Reproduction Steps: Clear, manual steps to reproduce the vulnerability.
|
||||
|
||||
## Security Model
|
||||
|
||||
This section defines what Apache Superset considers a security issue and what it does not. It is the canonical reference for reporters, the Apache Superset Security Team, and any automated tool (LLM-based scanner, static analyzer, dependency tool) that needs to constrain its hypotheses to behaviors that genuinely violate the project's security policy.
|
||||
|
||||
The model is intentionally written in terms of principals, trust boundaries, and capability surface rather than in terms of specific files, functions, or libraries. New code paths inherit the model automatically.
|
||||
|
||||
### Trust Boundaries
|
||||
|
||||
Apache Superset's threat model assumes three trust boundaries.
|
||||
|
||||
1. *The Admin role* is a fully trusted operational principal. Anything an Admin can do through the documented user interface, REST API, or configuration system is an intended capability, not a vulnerability, even if individually powerful or destructive. The Admin role is, by policy, equivalent to operating-system-level trust over the Apache Superset application. This is unavoidable rather than aspirational: an Admin can, for example, register new database connections of arbitrary type, execute arbitrary SQL through SQL Lab, render Jinja templates that resolve to SQL or rendered HTML, and override application configuration. Granting Admin is functionally equivalent to granting shell access on the host, which is the reasoning behind treating it as a trust boundary in the sense of MITRE CNA Operational Rules 4.1.
|
||||
|
||||
2. *The operator* is whoever deploys, configures, and runs Apache Superset. Behaviors that depend on deployment-time decisions are the operator's responsibility, not Apache Superset's. This includes the values of secrets, the network reachability of the application and its data sources, the choice of database connectors and cache backends, the selection of feature flags, the destinations of notifications, and the trust placed in third-party plugins. Defaults that fail closed are the responsibility of the Apache Superset codebase. Defaults that fail open must be accompanied by a documented hardening requirement; applying that hardening is the operator's responsibility, while shipping an undocumented or unflagged fail-open default is a codebase issue.
|
||||
|
||||
3. *The Apache Superset codebase* is responsible for enforcing the role and capability matrix below across its product surface. A failure to enforce, anywhere in that surface, is in scope. The codebase's commitments are limited to the role and capability matrix and to controls Apache Superset's own documentation (this file and the linked Security documentation) explicitly positions as security boundaries; configurable hardening that operators can layer on top is treated separately under *Vulnerability Scope* below.
|
||||
|
||||
### Roles and Capabilities
|
||||
|
||||
Apache Superset ships with the following first-class principals. Detailed permission definitions live in the [Security documentation](https://superset.apache.org/docs/security).
|
||||
|
||||
| Principal | Read data | Write objects | Execute SQL | Manage databases | Manage users, roles, RLS |
|
||||
|---|---|---|---|---|---|
|
||||
| Public (anonymous) | none by default | no | no | no | no |
|
||||
| Gamma | only granted datasets | own charts and dashboards on granted datasets | no by default (requires the `sql_lab` role) | no | no |
|
||||
| Alpha | all data sources | own charts, dashboards, and datasets | no by default (requires the `sql_lab` role) | data upload to existing databases only | no |
|
||||
| Admin | all | all | yes | yes | yes |
|
||||
| Embedded guest token | data sources reachable through the embedded dashboards the token authorizes | no | no | no | no |
|
||||
|
||||
The `sql_lab` role is *additive*: it grants the SQL Lab permission set on top of the base role above, and is the only path by which Gamma or Alpha gain SQL execution capability. Database access is still scoped per the base role's grants. Admin includes SQL Lab access by default.
|
||||
|
||||
Deployments may grant or revoke individual view-menu permissions, which shifts the boundary for that deployment but does not redefine the model. Any custom role created by an operator inherits the same principle: its capabilities are whatever the operator has explicitly granted it. The Public principal follows the same rule: operators may grant the Public role read access to specific datasets or dashboards (typically for anonymous reporting use cases), which shifts the boundary for that deployment without redefining the model.
|
||||
|
||||
### Vulnerability Scope
|
||||
|
||||
The test for whether a finding is in scope is a single question:
|
||||
|
||||
> *Does this finding let a principal perform an action the role and capability matrix above does not entitle them to?*
|
||||
|
||||
If yes, it is in scope. If no, it is out of scope. The lists below apply that test to the classes Apache Superset most commonly receives reports about; they are illustrative, not exhaustive.
|
||||
|
||||
*In Scope*
|
||||
|
||||
- A user, embedded guest, or anonymous visitor reads, modifies, or deletes data outside their granted set. Includes object-level access bypass on charts, dashboards, datasets, saved queries, tags, annotations, and similar per-object endpoints, and row-level-security rule bypass.
|
||||
- A user supplies input that the codebase should sanitize or parameterize but does not, causing arbitrary SQL, template code, or scripts to execute. Includes injection through Jinja templates, SQL-construction paths, and any field the codebase passes to a query engine or template engine.
|
||||
- A user bypasses authentication, fixates or reuses another user's session, or reaches an authenticated endpoint without logging in.
|
||||
- An embedded guest token authorizes actions outside the dashboard it was issued for, or can be forged, replayed, or escalated to a higher principal.
|
||||
- Apache Superset, acting on behalf of an unprivileged user, fetches an outbound URL the user controls in a feature where Apache Superset itself, not the operator, controls the outbound destination set (server-side request forgery).
|
||||
- An Apache Superset default fails open without an accompanying documented hardening requirement. The codebase is responsible for shipping fail-closed defaults or for documenting the hardening required when a default fails open; failures of that responsibility are in scope (see *Trust Boundaries*).
|
||||
- A user bypasses a control Apache Superset documents specifically as a security boundary. This includes row-level security, the access checks tied to the role and capability matrix above, and any feature whose documentation positions it as security-relevant. The codebase commits to enforcing those controls; bypasses are in scope regardless of which principal triggers them.
|
||||
- A user causes a script to execute in another user's browser through a field the codebase renders to that other user (cross-site scripting), or causes cross-origin leakage of authenticated session state or data.
|
||||
- A user reaches a route, page, or API endpoint that requires a role they do not have.
|
||||
|
||||
*Out of Scope*
|
||||
|
||||
- Any action an Admin role can perform through documented configuration, API, or UI. The Admin role is a trusted operational principal by policy. Per MITRE CNA Operational Rules 4.1, a qualifying vulnerability must violate a security policy; behavior within a documented trust boundary does not.
|
||||
- Deployment or operator decisions: the values of secrets and tokens, whether internal networks are reachable from the server, which database connectors or cache backends are enabled, which feature flags are set, where notifications are delivered, and which third-party plugins are loaded.
|
||||
- Compromise, modification, or malicious control of trusted backend infrastructure. Apache Superset assumes the integrity of its metastore, cache backends (for example Redis or Memcached), message brokers, secret stores, and other operator-managed infrastructure. Findings that require an attacker to read from, write to, or otherwise tamper with these systems, including injecting malicious state, serialized objects, cache entries, task metadata, configuration, or database records, are post-compromise scenarios and do not constitute vulnerabilities in Apache Superset itself. A finding remains in scope only if an unprivileged user can cause such modification through a vulnerability in Apache Superset.
|
||||
- The continued presence of expired key-value or metastore-cache entries that have not yet been deleted from the metadata database. Such entries are excluded from reads once expired, are purged opportunistically on write, and are removed in bulk by the scheduled `prune_key_value` maintenance task; their lingering until purged is an eventual-cleanup property, not a security boundary, and does not constitute a vulnerability.
|
||||
- How a downstream application (spreadsheet program, email client, browser handling user-downloaded files) interprets output Apache Superset produced for it.
|
||||
- Findings without a reproducible proof of concept against a supported release. The burden of demonstrating exploitability rests with the reporter; findings closed for lack of a proof of concept may be refiled if one is later produced.
|
||||
- Brute force, rate limiting, denial of service, or resource exhaustion that does not bypass a documented control.
|
||||
- Missing security headers, banner or version disclosure, user or object enumeration through error messages or timing, and similar low-impact information disclosure that does not enable a further concrete exploit.
|
||||
- Bypasses of configurable defense-in-depth hardening that Apache Superset does not document as a security boundary. Apache Superset is not a SQL or database firewall: operator-deployable filters such as SQL function or table denylists, URI restrictions on already-authorized database connectors, and similar belt-and-braces controls are provided to let operators layer hardening on top of the role and capability matrix, not as firewall-grade guarantees the codebase commits to. Findings against such hardening are improvements, not vulnerabilities, unless the documentation positions the specific control as security-relevant.
|
||||
- Hardening suggestions that improve defense in depth but do not violate the security model.
|
||||
|
||||
Findings in third-party dependencies fall into two cases. A finding in a transitive dependency, or in an operator-selected dependency that Apache Superset does not ship, is out of scope and should be reported to the dependency's maintainers. A finding caused by Apache Superset pinning a known-vulnerable version of a direct dependency it ships, or using a dependency in a way that creates a vulnerability the dependency itself does not have, remains in scope. Dependency findings in the official Apache Superset Docker image that fall into the first case can be remediated by extending the image at release time.
|
||||
|
||||
When uncertain whether a finding falls in scope, please file it through the reporting process above. The triage team will classify it and explain the reasoning if it is closed as out of scope.
|
||||
|
||||
**Outcome of Reports**
|
||||
|
||||
Reports that are deemed out of scope for a CVE but represent valid security best practices or hardening opportunities are typically converted into public GitHub issues, where the community can contribute fixes alongside the maintainers. The triage decision and reasoning are communicated back to the reporter in either case.
|
||||
|
||||
**Vulnerability Aggregation & CVE Attribution**
|
||||
|
||||
In accordance with MITRE CNA Operational Rules (4.1.10, 4.1.11, and 4.2.13), Apache Superset issues CVEs based on the underlying architectural root cause rather than the number of affected endpoints or exploit payloads.
|
||||
- Aggregation: If multiple exploit vectors stem from the same programmatic failure or shared vulnerable code, they must be aggregated into a single, comprehensive report.
|
||||
- Independent Fixes: Separate CVEs will only be assigned if the vulnerabilities reside in decoupled architectural modules and can be fixed independently of one another.
|
||||
Reports that fail to aggregate related findings will be merged during triage to ensure an accurate and defensible CVE record.
|
||||
|
||||
**Your responsible disclosure and collaboration are invaluable.**
|
||||
|
||||
## Extra Information
|
||||
|
||||
- [Apache Superset documentation](https://superset.apache.org/docs/security)
|
||||
- [Common Vulnerabilities and Exposures by release](https://superset.apache.org/docs/security/cves)
|
||||
- [How Security Vulnerabilities are Reported & Handled in Apache Superset (Blog)](https://preset.io/blog/how-security-vulnerabilities-are-reported-and-handled-in-apache-superset/)
|
||||
|
||||
**For LLM agents and automated scanners**
|
||||
|
||||
This file is the canonical source of truth for what Apache Superset considers a security vulnerability. Automated tooling (LLM-based code scanners, static analyzers, dependency tools) should treat the Security Model section as authoritative when classifying findings. The repository's [AGENTS.md](AGENTS.md) file contains a short pointer to this document for agents that read AGENTS.md as their entry point.
|
||||
354
UPDATING.md
354
UPDATING.md
@@ -23,348 +23,6 @@ This file documents any backwards-incompatible changes in Superset and
|
||||
assists people when migrating to a new version.
|
||||
|
||||
## Next
|
||||
|
||||
### Duration formatter precision
|
||||
|
||||
The `DURATION` number formatter now uses `Intl.DurationFormat` for locale-aware output. By default, sub-second fields are omitted, so values that previously displayed fractional seconds with `pretty-ms`, such as `10500` milliseconds rendering as `10.5s`, now render as `10s`.
|
||||
|
||||
To preserve sub-second precision in custom duration formatters, enable `formatSubMilliseconds`.
|
||||
|
||||
### Cache warmup authenticates via SUPERSET_CACHE_WARMUP_USER
|
||||
|
||||
The `cache-warmup` Celery task now drives a real WebDriver session for reliable authentication and reads the user to authenticate as from the new `SUPERSET_CACHE_WARMUP_USER` config option. It no longer consults `CACHE_WARMUP_EXECUTORS` for the warmup path. `SUPERSET_CACHE_WARMUP_USER` defaults to `None`, so the task fails fast with a clear message until you set it. Operators who previously relied on `CACHE_WARMUP_EXECUTORS` for cache warmup must set `SUPERSET_CACHE_WARMUP_USER` to a dedicated least-privilege user with access to the dashboards they want warmed up before the next warmup run.
|
||||
|
||||
### YDB now uses a native sqlglot dialect
|
||||
|
||||
YDB SQL parsing now relies on the dedicated [`ydb-sqlglot-plugin`](https://pypi.org/project/ydb-sqlglot-plugin/) dialect, which registers itself with sqlglot automatically. YDB users must install this plugin (e.g., via `pip install "apache-superset[ydb]"`) to avoid a `ValueError` when Superset parses YDB queries.
|
||||
|
||||
### Embedded dashboards enforce configured Allowed Domains for postMessage
|
||||
|
||||
The embedded dashboard page now validates the origin of incoming `postMessage` events against the dashboard's configured **Allowed Domains**. The server-rendered embedded page exposes the configured domains in its bootstrap payload, and the frontend rejects message events whose origin is not in that list.
|
||||
|
||||
Enforcement only applies when the Allowed Domains list is non-empty. If the list is empty (the default), any origin is accepted, so there is no behavior change for embeds that did not configure Allowed Domains.
|
||||
|
||||
### Default guest/async JWT secrets are rejected at startup
|
||||
|
||||
Superset already refuses to start in production (non-debug, non-testing) when `SECRET_KEY` is left at its built-in default, and when `GUEST_TOKEN_JWT_SECRET` is left at its default while `EMBEDDED_SUPERSET` is enabled. This behavior is extended to `GLOBAL_ASYNC_QUERIES_JWT_SECRET`: if the `GLOBAL_ASYNC_QUERIES` feature flag is enabled and the secret is still the publicly known default (`test-secret-change-me`), Superset logs a clear error and refuses to start.
|
||||
|
||||
As with the existing `SECRET_KEY` check, this only fails in production. In debug mode, testing mode, or under the test runner, a warning is logged instead of exiting, so local development is unaffected.
|
||||
|
||||
To resolve the error, set a strong random value in `superset_config.py`:
|
||||
|
||||
```python
|
||||
GLOBAL_ASYNC_QUERIES_JWT_SECRET = "<output of: openssl rand -base64 42>"
|
||||
```
|
||||
|
||||
The check is only active when the relevant feature is enabled, so deployments that do not use global async queries (or embedding) are not affected.
|
||||
|
||||
### Dataset import validates catalog against the target connection
|
||||
|
||||
Importing a dataset now validates the `catalog` field against the target database connection. When the connection has multi-catalog disabled (`allow_multi_catalog` off) and the dataset's catalog is not the connection's default catalog, the import fails instead of silently persisting the non-default catalog. This matches the validation already enforced on the dataset update path and prevents imported datasets from querying an unintended database.
|
||||
|
||||
If you relied on importing datasets with a non-default catalog, enable "Allow changing catalogs" on the target connection, or set the dataset's catalog to the connection's default before importing.
|
||||
|
||||
### Extension supply-chain controls (denylist + version policy)
|
||||
|
||||
Two opt-in static gates control which extensions are allowed to load:
|
||||
|
||||
- `EXTENSION_DENYLIST` refuses extensions matching an id (every version) or `id@version` (a single version), e.g. `["compromised-extension", "other-ext@1.2.3"]`.
|
||||
- `EXTENSION_VERSION_POLICY` enforces a minimum version per extension id, e.g. `{"acme.widget": "1.2.0"}` (PEP 440 comparison); a release below the minimum is refused.
|
||||
|
||||
Both default to empty (no behavior change). They apply to both the `LOCAL_EXTENSIONS` and `EXTENSIONS_PATH` load paths.
|
||||
|
||||
### Dynamic Group By respects the sort toggle for display values
|
||||
|
||||
The Dynamic Group By chart customization now orders its display values according to the "Sort display control values" toggle: ascending (A–Z), descending (Z–A), or the dataset's source order when the toggle is unset. Previously the dropdown always sorted alphabetically. Existing dashboards where the toggle was never set will show options in source order instead of A–Z; open the customization and enable the toggle to restore alphabetical ordering.
|
||||
|
||||
### Granular Export Controls
|
||||
|
||||
A new feature flag `GRANULAR_EXPORT_CONTROLS` introduces three fine-grained permissions that replace the legacy `can_csv` permission:
|
||||
|
||||
| Permission | Controls |
|
||||
|---|---|
|
||||
| `can_export_data` | CSV, Excel, JSON exports |
|
||||
| `can_export_image` | Screenshot/PDF exports |
|
||||
| `can_copy_clipboard` | Copy-to-clipboard operations |
|
||||
|
||||
When the feature flag is enabled, these permissions are enforced on both the frontend (disabled buttons with tooltips) and backend (403 responses from API endpoints). When disabled, legacy `can_csv` behavior is preserved.
|
||||
|
||||
**Migration behavior:** All three new permissions are granted to every role that currently has `can_csv`, preserving existing access. Admins can then selectively revoke individual export permissions from specific roles as needed.
|
||||
|
||||
### Deck.gl MapBox viewport and opacity controls are functional
|
||||
|
||||
The Deck.gl MapBox chart's **Opacity**, **Default longitude**, **Default latitude**, and **Zoom** controls were previously non-functional — changing them had no effect on the rendered map. These controls are now wired up correctly.
|
||||
|
||||
**Behavior change for existing charts:** Previously, the viewport controls had hard-coded default values (`-122.405293`, `37.772123`, zoom `11` — San Francisco) that were stored in each chart's `form_data` but never applied. The map always used `fitBounds` to center on the data. With this fix, those stored values are now respected, which means existing MapBox charts may open centered on the old default coordinates instead of fitting to data bounds.
|
||||
|
||||
**To restore fit-to-data behavior:** Open the chart in Explore, clear the **Default longitude**, **Default latitude**, and **Zoom** fields in the Viewport section, and re-save the chart.
|
||||
|
||||
### Combined datasource list endpoint
|
||||
|
||||
Added a new combined datasource list endpoint at `GET /api/v1/datasource/` to serve datasets and semantic views in one response.
|
||||
|
||||
- The endpoint is available to users with at least one of `can_read` on `Dataset` or `SemanticView`.
|
||||
- Semantic views are included only when the `SEMANTIC_LAYERS` feature flag is enabled.
|
||||
- The endpoint enforces strict `order_column` validation and returns `400` for invalid sort columns.
|
||||
### ClickHouse minimum driver version bump
|
||||
|
||||
The minimum required version of `clickhouse-connect` has been raised to `>=0.13.0`. If you are using the ClickHouse connector, please upgrade your `clickhouse-connect` package. The `_mutate_label` workaround that appended hash suffixes to column aliases has also been removed, as it is no longer needed with modern versions of the driver.
|
||||
|
||||
### MCP Tool Observability
|
||||
|
||||
MCP (Model Context Protocol) tools now include enhanced observability instrumentation for monitoring and debugging:
|
||||
|
||||
**Two-layer instrumentation:**
|
||||
1. **Middleware layer** (`LoggingMiddleware`): Automatically logs all MCP tool calls with `duration_ms` and `success` status in the audit log (Action Log UI, logs table)
|
||||
2. **Sub-operation tracking**: All 19 MCP tools include granular `event_logger.log_context()` blocks for tracking individual operations like validation, database writes, and query execution
|
||||
|
||||
**Action naming convention:**
|
||||
- Tool-level logs: `mcp_tool_call` (via middleware)
|
||||
- Sub-operation logs: `mcp.{tool_name}.{operation}` (e.g., `mcp.generate_chart.validation`, `mcp.execute_sql.query_execution`)
|
||||
|
||||
**Querying MCP logs:**
|
||||
```sql
|
||||
-- Top slowest MCP operations
|
||||
SELECT action, COUNT(*) as calls, AVG(duration_ms) as avg_ms
|
||||
FROM logs
|
||||
WHERE action LIKE 'mcp.%'
|
||||
GROUP BY action
|
||||
ORDER BY avg_ms DESC
|
||||
LIMIT 20;
|
||||
|
||||
-- MCP tool success rate
|
||||
SELECT
|
||||
json_extract(curated_payload, '$.tool') as tool,
|
||||
COUNT(*) as total_calls,
|
||||
SUM(CASE WHEN json_extract(curated_payload, '$.success') = 'true' THEN 1 ELSE 0 END) as successful,
|
||||
ROUND(100.0 * SUM(CASE WHEN json_extract(curated_payload, '$.success') = 'true' THEN 1 ELSE 0 END) / COUNT(*), 2) as success_rate
|
||||
FROM logs
|
||||
WHERE action = 'mcp_tool_call'
|
||||
GROUP BY tool
|
||||
ORDER BY total_calls DESC;
|
||||
```
|
||||
|
||||
**Security note:** Sensitive parameters (passwords, API keys, tokens) are automatically redacted in logs as `[REDACTED]`.
|
||||
|
||||
### Distributed Coordination Backend
|
||||
|
||||
A new `DISTRIBUTED_COORDINATION_CONFIG` configuration provides a unified Redis-based backend for real-time coordination features in Superset. This backend enables:
|
||||
|
||||
- **Pub/sub messaging** for real-time event notifications between workers
|
||||
- **Atomic distributed locking** using Redis SET NX EX (more performant than database-backed locks)
|
||||
- **Event-based coordination** for background task management
|
||||
|
||||
The distributed coordination is used by the Global Task Framework (GTF) for abort notifications and task completion signaling, and will eventually replace `GLOBAL_ASYNC_QUERIES_CACHE_BACKEND` as the standard signaling backend. Configuring this is recommended for Redis enabled production deployments.
|
||||
|
||||
Example configuration in `superset_config.py`:
|
||||
```python
|
||||
DISTRIBUTED_COORDINATION_CONFIG = {
|
||||
"CACHE_TYPE": "RedisCache",
|
||||
"CACHE_KEY_PREFIX": "signal_",
|
||||
"CACHE_REDIS_URL": "redis://localhost:6379/1",
|
||||
"CACHE_DEFAULT_TIMEOUT": 300,
|
||||
}
|
||||
```
|
||||
|
||||
See `superset/config.py` for complete configuration options.
|
||||
|
||||
### WebSocket config for GAQ with Docker
|
||||
|
||||
[35896](https://github.com/apache/superset/pull/35896) and [37624](https://github.com/apache/superset/pull/37624) updated documentation on how to run and configure Superset with Docker. Specifically for the WebSocket configuration, a new `docker/superset-websocket/config.example.json` was added to the repo, so that users could copy it to create a `docker/superset-websocket/config.json` file. The existing `docker/superset-websocket/config.json` was removed and git-ignored, so if you're using GAQ / WebSocket make sure to:
|
||||
- Stash/backup your existing `config.json` file, to re-apply it after (will get git-ignored going forward)
|
||||
- Update the `volumes` configuration for the `superset-websocket` service in your `docker-compose.override.yml` file, to include the `docker/superset-websocket/config.json` file. For example:
|
||||
``` yaml
|
||||
services:
|
||||
superset-websocket:
|
||||
volumes:
|
||||
- ./superset-websocket:/home/superset-websocket
|
||||
- /home/superset-websocket/node_modules
|
||||
- /home/superset-websocket/dist
|
||||
- ./docker/superset-websocket/config.json:/home/superset-websocket/config.json:ro
|
||||
```
|
||||
|
||||
### Example Data Loading Improvements
|
||||
|
||||
#### New Directory Structure
|
||||
Examples are now organized by name with data and configs co-located:
|
||||
```
|
||||
superset/examples/
|
||||
├── _shared/ # Shared database & metadata configs
|
||||
├── birth_names/ # Each example is self-contained
|
||||
│ ├── data.parquet # Dataset (Parquet format)
|
||||
│ ├── dataset.yaml # Dataset metadata
|
||||
│ ├── dashboard.yaml # Dashboard config (optional)
|
||||
│ └── charts/ # Chart configs (optional)
|
||||
└── ...
|
||||
```
|
||||
|
||||
#### Simplified Parquet-based Loading
|
||||
- Auto-discovery: create `superset/examples/my_dataset/data.parquet` to add a new example
|
||||
- Parquet is an Apache project format: compressed (~27% smaller), self-describing schema
|
||||
- YAML configs define datasets, charts, and dashboards declaratively
|
||||
- Removed Python-based data generation from individual example files
|
||||
|
||||
#### Test Data Reorganization
|
||||
- Moved `big_data.py` to `superset/cli/test_loaders.py` - better reflects its purpose as a test utility
|
||||
- Fixed inverted logic for `--load-test-data` flag (now correctly includes .test.yaml files when flag is set)
|
||||
- Clarified CLI flags:
|
||||
- `--force` / `-f`: Force reload even if tables exist
|
||||
- `--only-metadata` / `-m`: Create table metadata without loading data
|
||||
- `--load-test-data` / `-t`: Include test dashboards and .test.yaml configs
|
||||
- `--load-big-data` / `-b`: Generate synthetic stress-test data
|
||||
|
||||
#### Bug Fixes
|
||||
- Fixed numpy array serialization for PostgreSQL (converts complex types to JSON strings)
|
||||
- Fixed KeyError for `allow_csv_upload` field in database configs (now optional with default)
|
||||
- Fixed test data loading logic that was incorrectly filtering files
|
||||
|
||||
### MCP Service
|
||||
|
||||
The MCP (Model Context Protocol) service enables AI assistants and automation tools to interact programmatically with Superset.
|
||||
|
||||
#### New Features
|
||||
- MCP service infrastructure with FastMCP framework
|
||||
- Tools for dashboards, charts, datasets, SQL Lab, and instance metadata
|
||||
- Optional dependency: install with `pip install apache-superset[fastmcp]`
|
||||
- Runs as separate process from Superset web server
|
||||
- JWT-based authentication for production deployments
|
||||
|
||||
#### New Configuration Options
|
||||
|
||||
**Development** (single-user, local testing):
|
||||
```python
|
||||
# superset_config.py
|
||||
MCP_DEV_USERNAME = "admin" # User for MCP authentication
|
||||
MCP_SERVICE_HOST = "localhost"
|
||||
MCP_SERVICE_PORT = 5008
|
||||
```
|
||||
|
||||
**Production** (JWT-based, multi-user):
|
||||
```python
|
||||
# superset_config.py
|
||||
MCP_AUTH_ENABLED = True
|
||||
MCP_JWT_ISSUER = "https://your-auth-provider.com"
|
||||
MCP_JWT_AUDIENCE = "superset-mcp"
|
||||
MCP_JWT_ALGORITHM = "RS256" # or "HS256" for shared secrets
|
||||
|
||||
# Option 1: Use JWKS endpoint (recommended for RS256)
|
||||
MCP_JWKS_URI = "https://auth.example.com/.well-known/jwks.json"
|
||||
|
||||
# Option 2: Use static public key (RS256)
|
||||
MCP_JWT_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----..."
|
||||
|
||||
# Option 3: Use shared secret (HS256)
|
||||
MCP_JWT_ALGORITHM = "HS256"
|
||||
MCP_JWT_SECRET = "your-shared-secret-key"
|
||||
|
||||
# Optional overrides
|
||||
MCP_SERVICE_HOST = "0.0.0.0"
|
||||
MCP_SERVICE_PORT = 5008
|
||||
MCP_SESSION_CONFIG = {
|
||||
"SESSION_COOKIE_SECURE": True,
|
||||
"SESSION_COOKIE_HTTPONLY": True,
|
||||
"SESSION_COOKIE_SAMESITE": "Strict",
|
||||
}
|
||||
```
|
||||
|
||||
#### Running the MCP Service
|
||||
|
||||
```bash
|
||||
# Development
|
||||
superset mcp run --port 5008 --debug
|
||||
|
||||
# Production
|
||||
superset mcp run --port 5008
|
||||
|
||||
# With factory config
|
||||
superset mcp run --port 5008 --use-factory-config
|
||||
```
|
||||
|
||||
#### Deployment Considerations
|
||||
|
||||
The MCP service runs as a **separate process** from the Superset web server.
|
||||
|
||||
**Important**:
|
||||
- Requires same Python environment and configuration as Superset
|
||||
- Shares database connections with main Superset app
|
||||
- Can be scaled independently from web server
|
||||
- Requires `fastmcp` package (optional dependency)
|
||||
|
||||
**Installation**:
|
||||
```bash
|
||||
# Install with MCP support
|
||||
pip install apache-superset[fastmcp]
|
||||
|
||||
# Or add to requirements.txt
|
||||
apache-superset[fastmcp]>=X.Y.Z
|
||||
```
|
||||
|
||||
**Process Management**:
|
||||
Use systemd, supervisord, or Kubernetes to manage the MCP service process.
|
||||
See `superset/mcp_service/PRODUCTION.md` for deployment guides.
|
||||
|
||||
**Security**:
|
||||
- Development: Uses `MCP_DEV_USERNAME` for single-user access
|
||||
- Production: **MUST** configure JWT authentication
|
||||
- See `superset/mcp_service/SECURITY.md` for details
|
||||
|
||||
#### Documentation
|
||||
|
||||
- Architecture: `superset/mcp_service/ARCHITECTURE.md`
|
||||
- Security: `superset/mcp_service/SECURITY.md`
|
||||
- Production: `superset/mcp_service/PRODUCTION.md`
|
||||
- Developer Guide: `superset/mcp_service/CLAUDE.md`
|
||||
- Quick Start: `superset/mcp_service/README.md`
|
||||
|
||||
---
|
||||
|
||||
- [35621](https://github.com/apache/superset/pull/35621): The default hash algorithm has changed from MD5 to SHA-256 for improved security and FedRAMP compliance. This affects cache keys for thumbnails, dashboard digests, chart digests, and filter option names. Existing cached data will be invalidated upon upgrade. To opt out of this change and maintain backward compatibility, set `HASH_ALGORITHM = "md5"` in your `superset_config.py`.
|
||||
- [35062](https://github.com/apache/superset/pull/35062): Changed the function signature of `setupExtensions` to `setupCodeOverrides` with options as arguments.
|
||||
|
||||
### Breaking Changes
|
||||
- [37370](https://github.com/apache/superset/pull/37370): The `APP_NAME` configuration variable no longer controls the browser window/tab title or other frontend branding. Application names should now be configured using the theme system with the `brandAppName` token. The `APP_NAME` config is still used for backend contexts (MCP service, logs, etc.) and serves as a fallback if `brandAppName` is not set.
|
||||
- **Migration:**
|
||||
```python
|
||||
# Before (Superset 5.x)
|
||||
APP_NAME = "My Custom App"
|
||||
|
||||
# After (Superset 6.x) - Option 1: Use theme system (recommended)
|
||||
THEME_DEFAULT = {
|
||||
"token": {
|
||||
"brandAppName": "My Custom App", # Window titles
|
||||
"brandLogoAlt": "My Custom App", # Logo alt text
|
||||
"brandLogoUrl": "/static/assets/images/custom_logo.png"
|
||||
}
|
||||
}
|
||||
|
||||
# After (Superset 6.x) - Option 2: Temporary fallback
|
||||
# Keep APP_NAME for now (will be used as fallback for brandAppName)
|
||||
APP_NAME = "My Custom App"
|
||||
# But you should migrate to THEME_DEFAULT.token.brandAppName
|
||||
```
|
||||
- **Note:** For dark mode, set the same tokens in `THEME_DARK` configuration.
|
||||
|
||||
- [36317](https://github.com/apache/superset/pull/36317): The `CUSTOM_FONT_URLS` configuration option has been removed. Use the new per-theme `fontUrls` token in `THEME_DEFAULT` or database-managed themes instead.
|
||||
- **Before:**
|
||||
```python
|
||||
CUSTOM_FONT_URLS = [
|
||||
"https://fonts.example.com/myfont.css",
|
||||
]
|
||||
```
|
||||
- **After:**
|
||||
```python
|
||||
THEME_DEFAULT = {
|
||||
"token": {
|
||||
"fontUrls": [
|
||||
"https://fonts.example.com/myfont.css",
|
||||
],
|
||||
# ... other tokens
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 6.0.0
|
||||
- [33055](https://github.com/apache/superset/pull/33055): Upgrades Flask-AppBuilder to 5.0.0. The AUTH_OID authentication type has been deprecated and is no longer available as an option in Flask-AppBuilder. OpenID (OID) is considered a deprecated authentication protocol - if you are using AUTH_OID, you will need to migrate to an alternative authentication method such as OAuth, LDAP, or database authentication before upgrading.
|
||||
- [34871](https://github.com/apache/superset/pull/34871): Fixed Jest test hanging issue from Ant Design v5 upgrade. MessageChannel is now mocked in test environment to prevent rc-overflow from causing Jest to hang. Test environment only - no production impact.
|
||||
- [34782](https://github.com/apache/superset/pull/34782): Dataset exports now include the dataset ID in their file name (similar to charts and dashboards). If managing assets as code, make sure to rename existing dataset YAMLs to include the ID (and avoid duplicated files).
|
||||
- [34536](https://github.com/apache/superset/pull/34536): The `ENVIRONMENT_TAG_CONFIG` color values have changed to support only Ant Design semantic colors. Update your `superset_config.py`:
|
||||
@@ -381,14 +39,14 @@ Note: Pillow is now a required dependency (previously optional) to support image
|
||||
- [33116](https://github.com/apache/superset/pull/33116) In Echarts Series charts (e.g. Line, Area, Bar, etc.) charts, the `x_axis_sort_series` and `x_axis_sort_series_ascending` form data items have been renamed with `x_axis_sort` and `x_axis_sort_asc`.
|
||||
There's a migration added that can potentially affect a significant number of existing charts.
|
||||
- [32317](https://github.com/apache/superset/pull/32317) The horizontal filter bar feature is now out of testing/beta development and its feature flag `HORIZONTAL_FILTER_BAR` has been removed.
|
||||
- [31590](https://github.com/apache/superset/pull/31590) Marks the beginning of intricate work around supporting dynamic Theming, and breaks support for [THEME_OVERRIDES](https://github.com/apache/superset/blob/732de4ac7fae88e29b7f123b6cbb2d7cd411b0e4/superset/config.py#L671) in favor of a new theming system based on AntD V5. Likely this will be in disrepair until settling over the 5.x lifecycle.
|
||||
- [32432](https://github.com/apache/superset/pull/32432) Moves the List Roles FAB view to the frontend and requires `FAB_ADD_SECURITY_API` to be enabled in the configuration and `superset init` to be executed.
|
||||
- [31590](https://github.com/apache/superset/pull/31590) Marks the begining of intricate work around supporting dynamic Theming, and breaks support for [THEME_OVERRIDES](https://github.com/apache/superset/blob/732de4ac7fae88e29b7f123b6cbb2d7cd411b0e4/superset/config.py#L671) in favor of a new theming system based on AntD V5. Likely this will be in disrepair until settling over the 5.x lifecycle.
|
||||
- [32432](https://github.com/apache/superset/pull/31260) Moves the List Roles FAB view to the frontend and requires `FAB_ADD_SECURITY_API` to be enabled in the configuration and `superset init` to be executed.
|
||||
- [34319](https://github.com/apache/superset/pull/34319) Drill to Detail and Drill By is now supported in Embedded mode, and also with the `DASHBOARD_RBAC` FF. If you don't want to expose these features in Embedded / `DASHBOARD_RBAC`, make sure the roles used for Embedded / `DASHBOARD_RBAC`don't have the required permissions to perform D2D actions.
|
||||
|
||||
## 5.0.0
|
||||
|
||||
- [31976](https://github.com/apache/superset/pull/31976) Removed the `DISABLE_LEGACY_DATASOURCE_EDITOR` feature flag. The previous value of the feature flag was `True` and now the feature is permanently removed.
|
||||
- [32000](https://github.com/apache/superset/pull/32000) Removes CSV_UPLOAD_MAX_SIZE config, use your web server to control file upload size.
|
||||
- [31959](https://github.com/apache/superset/pull/32000) Removes CSV_UPLOAD_MAX_SIZE config, use your web server to control file upload size.
|
||||
- [31959](https://github.com/apache/superset/pull/31959) Removes the following endpoints from data uploads: `/api/v1/database/<id>/<file type>_upload` and `/api/v1/database/<file type>_metadata`, in favour of new one (Details on the PR). And simplifies permissions.
|
||||
- [31844](https://github.com/apache/superset/pull/31844) The `ALERT_REPORTS_EXECUTE_AS` and `THUMBNAILS_EXECUTE_AS` config parameters have been renamed to `ALERT_REPORTS_EXECUTORS` and `THUMBNAILS_EXECUTORS` respectively. A new config flag `CACHE_WARMUP_EXECUTORS` has also been introduced to be able to control which user is used to execute cache warmup tasks. Finally, the config flag `THUMBNAILS_SELENIUM_USER` has been removed. To use a fixed executor for async tasks, use the new `FixedExecutor` class. See the config and docs for more info on setting up different executor profiles.
|
||||
- [31894](https://github.com/apache/superset/pull/31894) Domain sharding is deprecated in favor of HTTP2. The `SUPERSET_WEBSERVER_DOMAINS` configuration will be removed in the next major version (6.0)
|
||||
@@ -396,7 +54,7 @@ Note: Pillow is now a required dependency (previously optional) to support image
|
||||
- [31774](https://github.com/apache/superset/pull/31774): Fixes the spelling of the `USE-ANALAGOUS-COLORS` feature flag. Please update any scripts/configuration item to use the new/corrected `USE-ANALOGOUS-COLORS` flag spelling.
|
||||
- [31582](https://github.com/apache/superset/pull/31582) Removed the legacy Area, Bar, Event Flow, Heatmap, Histogram, Line, Sankey, and Sankey Loop charts. They were all automatically migrated to their ECharts counterparts with the exception of the Event Flow and Sankey Loop charts which were removed as they were not actively maintained and not widely used. If you were using the Event Flow or Sankey Loop charts, you will need to find an alternative solution.
|
||||
- [31198](https://github.com/apache/superset/pull/31198) Disallows by default the use of the following ClickHouse functions: "version", "currentDatabase", "hostName".
|
||||
- [29798](https://github.com/apache/superset/pull/29798) Since 3.1.0, the initial schedule for an alert or report was mistakenly offset by the specified timezone's relation to UTC. The initial schedule should now begin at the correct time.
|
||||
- [29798](https://github.com/apache/superset/pull/29798) Since 3.1.0, the intial schedule for an alert or report was mistakenly offset by the specified timezone's relation to UTC. The initial schedule should now begin at the correct time.
|
||||
- [30021](https://github.com/apache/superset/pull/30021) The `dev` layer in our Dockerfile no long includes firefox binaries, only Chromium to reduce bloat/docker-build-time.
|
||||
- [30099](https://github.com/apache/superset/pull/30099) Translations are no longer included in the default docker image builds. If your environment requires translations, you'll want to set the docker build arg `BUILD_TRANSLATIONS=true`.
|
||||
- [31262](https://github.com/apache/superset/pull/31262) NOTE: deprecated `pylint` in favor of `ruff` as our only python linter. Only affect development workflows positively (not the release itself). It should cover most important rules, be much faster, but some things linting rules that were enforced before may not be enforce in the exact same way as before.
|
||||
@@ -409,7 +67,7 @@ Note: Pillow is now a required dependency (previously optional) to support image
|
||||
- [25166](https://github.com/apache/superset/pull/25166) Changed the default configuration of `UPLOAD_FOLDER` from `/app/static/uploads/` to `/static/uploads/`. It also removed the unused `IMG_UPLOAD_FOLDER` and `IMG_UPLOAD_URL` configuration options.
|
||||
- [30284](https://github.com/apache/superset/pull/30284) Deprecated GLOBAL_ASYNC_QUERIES_REDIS_CONFIG in favor of the new GLOBAL_ASYNC_QUERIES_CACHE_BACKEND configuration. To leverage Redis Sentinel, set CACHE_TYPE to RedisSentinelCache, or use RedisCache for standalone Redis
|
||||
- [31961](https://github.com/apache/superset/pull/31961) Upgraded React from version 16.13.1 to 17.0.2. If you are using custom frontend extensions or plugins, you may need to update them to be compatible with React 17.
|
||||
- [31260](https://github.com/apache/superset/pull/31260) Docker images now use `uv pip install` instead of `pip install` to manage the python environment. Most docker-based deployments will be affected, whether you derive one of the published images, or have custom bootstrap script that install python libraries (drivers)
|
||||
- [31260](https://github.com/apache/superset/pull/31260) Docker images now use `uv pip install` instead of `pip install` to manage the python envrionment. Most docker-based deployments will be affected, whether you derive one of the published images, or have custom bootstrap script that install python libraries (drivers)
|
||||
|
||||
### Potential Downtime
|
||||
|
||||
@@ -486,7 +144,7 @@ Note: Pillow is now a required dependency (previously optional) to support image
|
||||
- [26462](https://github.com/apache/superset/issues/26462): Removes the Profile feature given that it's not actively maintained and not widely used.
|
||||
- [26377](https://github.com/apache/superset/pull/26377): Removes the deprecated Redirect API that supported short URLs used before the permalink feature.
|
||||
- [26329](https://github.com/apache/superset/issues/26329): Removes the deprecated `DASHBOARD_NATIVE_FILTERS` feature flag. The previous value of the feature flag was `True` and now the feature is permanently enabled.
|
||||
- [25510](https://github.com/apache/superset/pull/25510): Reinforces that any newly defined Python data format (other than epoch) must adhere to the ISO 8601 standard (enforced by way of validation at the API and database level) after a previous relaxation to include slashes in addition to dashes. From now on when specifying new columns, dataset owners will need to use a SQL expression instead to convert their string columns of the form %Y/%m/%d etc. to a `DATE`, `DATETIME`, etc. type.
|
||||
- [25510](https://github.com/apache/superset/pull/25510): Reenforces that any newly defined Python data format (other than epoch) must adhere to the ISO 8601 standard (enforced by way of validation at the API and database level) after a previous relaxation to include slashes in addition to dashes. From now on when specifying new columns, dataset owners will need to use a SQL expression instead to convert their string columns of the form %Y/%m/%d etc. to a `DATE`, `DATETIME`, etc. type.
|
||||
- [26372](https://github.com/apache/superset/issues/26372): Removes the deprecated `GENERIC_CHART_AXES` feature flag. The previous value of the feature flag was `True` and now the feature is permanently enabled.
|
||||
|
||||
### Potential Downtime
|
||||
|
||||
@@ -28,7 +28,6 @@ x-superset-image: &superset-image apachesuperset.docker.scarf.sh/apache/superset
|
||||
x-superset-volumes:
|
||||
&superset-volumes # /app/pythonpath_docker will be appended to the PYTHONPATH in the final container
|
||||
- ./docker:/app/docker
|
||||
- ./superset-core:/app/superset-core
|
||||
- superset_home:/app/superset_home
|
||||
|
||||
services:
|
||||
@@ -45,7 +44,7 @@ services:
|
||||
required: true
|
||||
- path: docker/.env-local # optional override
|
||||
required: false
|
||||
image: postgres:17
|
||||
image: postgres:16
|
||||
container_name: superset_db
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
|
||||
@@ -77,6 +77,7 @@ x-common-build: &common-build
|
||||
INCLUDE_CHROMIUM: ${INCLUDE_CHROMIUM:-false}
|
||||
INCLUDE_FIREFOX: ${INCLUDE_FIREFOX:-false}
|
||||
BUILD_TRANSLATIONS: ${BUILD_TRANSLATIONS:-false}
|
||||
LOAD_EXAMPLES_DUCKDB: ${LOAD_EXAMPLES_DUCKDB:-true}
|
||||
|
||||
services:
|
||||
db-light:
|
||||
@@ -85,7 +86,7 @@ services:
|
||||
required: true
|
||||
- path: docker/.env-local # optional override
|
||||
required: false
|
||||
image: postgres:17
|
||||
image: postgres:16
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- db_home_light:/var/lib/postgresql/data
|
||||
@@ -115,10 +116,7 @@ services:
|
||||
DATABASE_HOST: db-light
|
||||
DATABASE_DB: superset_light
|
||||
POSTGRES_DB: superset_light
|
||||
EXAMPLES_HOST: db-light
|
||||
EXAMPLES_DB: superset_light
|
||||
EXAMPLES_USER: superset
|
||||
EXAMPLES_PASSWORD: superset
|
||||
SUPERSET__SQLALCHEMY_EXAMPLES_URI: "duckdb:////app/data/examples.duckdb"
|
||||
SUPERSET_CONFIG_PATH: /app/docker/pythonpath_dev/superset_config_docker_light.py
|
||||
GITHUB_HEAD_REF: ${GITHUB_HEAD_REF:-}
|
||||
GITHUB_SHA: ${GITHUB_SHA:-}
|
||||
@@ -141,10 +139,7 @@ services:
|
||||
DATABASE_HOST: db-light
|
||||
DATABASE_DB: superset_light
|
||||
POSTGRES_DB: superset_light
|
||||
EXAMPLES_HOST: db-light
|
||||
EXAMPLES_DB: superset_light
|
||||
EXAMPLES_USER: superset
|
||||
EXAMPLES_PASSWORD: superset
|
||||
SUPERSET__SQLALCHEMY_EXAMPLES_URI: "duckdb:////app/data/examples.duckdb"
|
||||
SUPERSET_CONFIG_PATH: /app/docker/pythonpath_dev/superset_config_docker_light.py
|
||||
healthcheck:
|
||||
disable: true
|
||||
@@ -165,14 +160,10 @@ services:
|
||||
BUILD_SUPERSET_FRONTEND_IN_DOCKER: true
|
||||
NPM_RUN_PRUNE: false
|
||||
SCARF_ANALYTICS: "${SCARF_ANALYTICS:-}"
|
||||
DISABLE_TS_CHECKER: "${DISABLE_TS_CHECKER:-true}"
|
||||
# configuring the dev-server to use the host.docker.internal to connect to the backend
|
||||
superset: "http://superset-light:8088"
|
||||
# Webpack dev server must bind to 0.0.0.0 to be accessible from outside the container
|
||||
WEBPACK_DEVSERVER_HOST: "${WEBPACK_DEVSERVER_HOST:-0.0.0.0}"
|
||||
WEBPACK_DEVSERVER_PORT: "${WEBPACK_DEVSERVER_PORT:-9000}"
|
||||
ports:
|
||||
- "${NODE_PORT:-9001}:9000" # Parameterized port, accessible on all interfaces
|
||||
- "127.0.0.1:${NODE_PORT:-9001}:9000" # Parameterized port
|
||||
command: ["/app/docker/docker-frontend.sh"]
|
||||
env_file:
|
||||
- path: docker/.env # default
|
||||
@@ -202,6 +193,7 @@ services:
|
||||
DATABASE_DB: test
|
||||
POSTGRES_DB: test
|
||||
SUPERSET__SQLALCHEMY_DATABASE_URI: postgresql+psycopg2://superset:superset@db-light:5432/test
|
||||
SUPERSET__SQLALCHEMY_EXAMPLES_URI: "duckdb:////app/data/examples.duckdb"
|
||||
SUPERSET_CONFIG: superset_test_config_light
|
||||
PYTHONPATH: /app/pythonpath:/app/docker/pythonpath_dev:/app
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ services:
|
||||
required: true
|
||||
- path: docker/.env-local # optional override
|
||||
required: false
|
||||
image: postgres:17
|
||||
image: postgres:16
|
||||
container_name: superset_db
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
|
||||
@@ -29,11 +29,9 @@ x-superset-volumes: &superset-volumes
|
||||
# /app/pythonpath_docker will be appended to the PYTHONPATH in the final container
|
||||
- ./docker:/app/docker
|
||||
- ./superset:/app/superset
|
||||
- ./superset-core:/app/superset-core
|
||||
- ./superset-frontend:/app/superset-frontend
|
||||
- superset_home:/app/superset_home
|
||||
- ./tests:/app/tests
|
||||
- superset_data:/app/data
|
||||
x-common-build: &common-build
|
||||
context: .
|
||||
target: ${SUPERSET_BUILD_TARGET:-dev} # can use `dev` (default) or `lean`
|
||||
@@ -44,6 +42,7 @@ x-common-build: &common-build
|
||||
INCLUDE_CHROMIUM: ${INCLUDE_CHROMIUM:-false}
|
||||
INCLUDE_FIREFOX: ${INCLUDE_FIREFOX:-false}
|
||||
BUILD_TRANSLATIONS: ${BUILD_TRANSLATIONS:-false}
|
||||
LOAD_EXAMPLES_DUCKDB: ${LOAD_EXAMPLES_DUCKDB:-true}
|
||||
|
||||
services:
|
||||
nginx:
|
||||
@@ -53,45 +52,22 @@ services:
|
||||
- path: docker/.env-local # optional override
|
||||
required: false
|
||||
image: nginx:latest
|
||||
container_name: superset_nginx
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${NGINX_PORT:-80}:80"
|
||||
- "80:80"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
volumes:
|
||||
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./docker/nginx/templates:/etc/nginx/templates:ro
|
||||
# Wait for the webpack dev server's manifest.json to be served before
|
||||
# starting nginx. This prevents 404s on static assets at startup. The
|
||||
# probe targets host.docker.internal so it works regardless of whether
|
||||
# the dev server runs in the superset-node container
|
||||
# (BUILD_SUPERSET_FRONTEND_IN_DOCKER=true, the default) or directly on
|
||||
# the host (BUILD_SUPERSET_FRONTEND_IN_DOCKER=false).
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
- |
|
||||
url="http://host.docker.internal:9000/static/assets/manifest.json"
|
||||
max_attempts=150 # ~5 minutes at 2s intervals
|
||||
echo "Waiting for webpack dev server at $url..."
|
||||
attempt=0
|
||||
until curl -sf --max-time 5 -o /dev/null "$url"; do
|
||||
attempt=$((attempt + 1))
|
||||
if [ "$attempt" -ge "$max_attempts" ]; then
|
||||
echo "ERROR: webpack dev server did not serve $url after $max_attempts attempts (~5 minutes)." >&2
|
||||
echo "Is the dev server running? With BUILD_SUPERSET_FRONTEND_IN_DOCKER=false you must start it on the host (e.g. 'npm run dev' in superset-frontend)." >&2
|
||||
exit 1
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
echo "Webpack dev server is ready; starting nginx."
|
||||
exec nginx -g 'daemon off;'
|
||||
|
||||
redis:
|
||||
image: redis:7
|
||||
container_name: superset_cache
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:${REDIS_PORT:-6379}:6379"
|
||||
- "127.0.0.1:6379:6379"
|
||||
volumes:
|
||||
- redis:/data
|
||||
|
||||
@@ -101,10 +77,11 @@ services:
|
||||
required: true
|
||||
- path: docker/.env-local # optional override
|
||||
required: false
|
||||
image: postgres:17
|
||||
image: postgres:16
|
||||
container_name: superset_db
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:${DATABASE_PORT:-5432}:5432"
|
||||
- "127.0.0.1:5432:5432"
|
||||
volumes:
|
||||
- db_home:/var/lib/postgresql/data
|
||||
- ./docker/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
|
||||
@@ -117,12 +94,13 @@ services:
|
||||
required: false
|
||||
build:
|
||||
<<: *common-build
|
||||
container_name: superset_app
|
||||
command: ["/app/docker/docker-bootstrap.sh", "app"]
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- ${SUPERSET_PORT:-8088}:8088
|
||||
- 8088:8088
|
||||
# When in cypress-mode ->
|
||||
- ${CYPRESS_PORT:-8081}:8081
|
||||
- 8081:8081
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
user: *superset-user
|
||||
@@ -130,11 +108,14 @@ services:
|
||||
superset-init:
|
||||
condition: service_completed_successfully
|
||||
volumes: *superset-volumes
|
||||
environment:
|
||||
SUPERSET__SQLALCHEMY_EXAMPLES_URI: "duckdb:////app/data/examples.duckdb"
|
||||
|
||||
superset-websocket:
|
||||
container_name: superset_websocket
|
||||
build: ./superset-websocket
|
||||
ports:
|
||||
- ${WEBSOCKET_PORT:-8080}:8080
|
||||
- 8080:8080
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
depends_on:
|
||||
@@ -154,9 +135,9 @@ services:
|
||||
- /home/superset-websocket/node_modules
|
||||
- /home/superset-websocket/dist
|
||||
|
||||
# Mount config file. Create your own docker/superset-websocket/config.json
|
||||
# for custom settings, then point to it here. Do not use this example in production.
|
||||
- ./docker/superset-websocket/config.example.json:/home/superset-websocket/config.json:ro
|
||||
# Mounting a config file that contains a dummy secret required to boot up.
|
||||
# do not use this docker compose in production
|
||||
- ./docker/superset-websocket/config.json:/home/superset-websocket/config.json
|
||||
environment:
|
||||
- PORT=8080
|
||||
- REDIS_HOST=redis
|
||||
@@ -166,6 +147,7 @@ services:
|
||||
superset-init:
|
||||
build:
|
||||
<<: *common-build
|
||||
container_name: superset_init
|
||||
command: ["/app/docker/docker-init.sh"]
|
||||
env_file:
|
||||
- path: docker/.env # default
|
||||
@@ -179,6 +161,8 @@ services:
|
||||
condition: service_started
|
||||
user: *superset-user
|
||||
volumes: *superset-volumes
|
||||
environment:
|
||||
SUPERSET__SQLALCHEMY_EXAMPLES_URI: "duckdb:////app/data/examples.duckdb"
|
||||
healthcheck:
|
||||
disable: true
|
||||
|
||||
@@ -200,10 +184,9 @@ services:
|
||||
SCARF_ANALYTICS: "${SCARF_ANALYTICS:-}"
|
||||
# configuring the dev-server to use the host.docker.internal to connect to the backend
|
||||
superset: "http://superset:8088"
|
||||
# Webpack dev server must bind to 0.0.0.0 to be accessible from outside the container
|
||||
WEBPACK_DEVSERVER_HOST: "0.0.0.0"
|
||||
ports:
|
||||
- "127.0.0.1:${NODE_PORT:-9000}:9000" # exposing the dynamic webpack dev server
|
||||
- "127.0.0.1:9000:9000" # exposing the dynamic webpack dev server
|
||||
container_name: superset_node
|
||||
command: ["/app/docker/docker-frontend.sh"]
|
||||
env_file:
|
||||
- path: docker/.env # default
|
||||
@@ -215,6 +198,7 @@ services:
|
||||
superset-worker:
|
||||
build:
|
||||
<<: *common-build
|
||||
container_name: superset_worker
|
||||
command: ["/app/docker/docker-bootstrap.sh", "worker"]
|
||||
env_file:
|
||||
- path: docker/.env # default
|
||||
@@ -240,6 +224,7 @@ services:
|
||||
superset-worker-beat:
|
||||
build:
|
||||
<<: *common-build
|
||||
container_name: superset_worker_beat
|
||||
command: ["/app/docker/docker-bootstrap.sh", "beat"]
|
||||
env_file:
|
||||
- path: docker/.env # default
|
||||
@@ -257,6 +242,7 @@ services:
|
||||
superset-tests-worker:
|
||||
build:
|
||||
<<: *common-build
|
||||
container_name: superset_tests_worker
|
||||
command: ["/app/docker/docker-bootstrap.sh", "worker"]
|
||||
env_file:
|
||||
- path: docker/.env # default
|
||||
@@ -288,5 +274,3 @@ volumes:
|
||||
external: false
|
||||
redis:
|
||||
external: false
|
||||
superset_data:
|
||||
external: false
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user