Compare commits

..

2 Commits

Author SHA1 Message Date
Chris Truter
2076d909d9 Run the tests please 2026-03-16 16:23:48 +02:00
Chris Truter
b2c2816d86 Switch branch of python-runner-container 2026-03-16 16:12:41 +02:00
3663 changed files with 512421 additions and 662225 deletions

View File

@@ -1,4 +1,4 @@
---
--b-
name: add-tracing
description: Add OpenTelemetry tracing spans to Clojure code following Metabase tracing conventions. Use when instrumenting backend code with trace coverage.
---

View File

@@ -1,173 +0,0 @@
---
name: clojure-eval
description: Evaluate Clojure code via nREPL using clj-nrepl-eval. Use this when you need to test code, check if edited files compile, verify function behavior, or interact with a running REPL session.
---
# Clojure REPL Evaluation
## When to Use This Skill
Use this skill when you need to:
- **Verify that edited Clojure files compile and load correctly**
- Test function behavior interactively
- Check the current state of the REPL
- Debug code by evaluating expressions
- Require or load namespaces for testing
- Validate that code changes work before committing
## How It Works
The `clj-nrepl-eval` command evaluates Clojure code against an nREPL server. **Session state persists between evaluations**, so you can require a namespace in one evaluation and use it in subsequent calls. Each host:port combination maintains its own session file.
## Instructions
### 0. Discover and select nREPL server
First, discover what nREPL servers are running in the current directory:
```bash
clj-nrepl-eval --discover-ports
```
This will show all nREPL servers (Clojure, Babashka, shadow-cljs, etc.) running in the current project directory.
**Then use the AskUserQuestion tool:**
- **If ports are discovered:** Prompt user to select which nREPL port to use:
- **question:** "Which nREPL port would you like to use?"
- **header:** "nREPL Port"
- **options:** Present each discovered port as an option with:
- **label:** The port number
- **description:** The server type and status (e.g., "Clojure nREPL server in current directory")
- Include up to 4 discovered ports as options
- The user can select "Other" to enter a custom port number
- **If no ports are discovered:** Prompt user how to start an nREPL server:
- **question:** "No nREPL servers found. How would you like to start one?"
- **header:** "Start nREPL"
- **options:**
- **label:** "deps.edn alias", **description:** "Find and use an nREPL alias in deps.edn"
- **label:** "Leiningen", **description:** "Start nREPL using 'lein repl'"
- The user can select "Other" for alternative methods or if they already have a server running on a specific port
IMPORTANT: IF you start a REPL do not supply a port let the nREPL start and return the port that it was started on.
### 1. Evaluate Clojure Code
> Evaluation automatically connects to the given port
Use the `-p` flag to specify the port and pass your Clojure code.
**Recommended: Pass code as a command-line argument:**
```bash
clj-nrepl-eval -p <PORT> "(+ 1 2 3)"
```
**For multiple expressions (single line):**
```bash
clj-nrepl-eval -p <PORT> "(def x 10) (+ x 20)"
```
**Alternative: Using heredoc (may require permission approval for multiline commands):**
```bash
clj-nrepl-eval -p <PORT> <<'EOF'
(def x 10)
(+ x 20)
EOF
```
**Alternative: Via stdin pipe:**
```bash
echo "(+ 1 2 3)" | clj-nrepl-eval -p <PORT>
```
### 2. Display nREPL Sessions
**Discover all nREPL servers in current directory:**
```bash
clj-nrepl-eval --discover-ports
```
Shows all running nREPL servers in the current project directory, including their type (clj/bb/basilisp) and whether they match the current working directory.
**Check previously connected sessions:**
```bash
clj-nrepl-eval --connected-ports
```
Shows only connections you have made before (appears after first evaluation on a port).
### 3. Common Patterns
**Require a namespace (always use :reload to pick up changes):**
```bash
clj-nrepl-eval -p <PORT> "(require '[my.namespace :as ns] :reload)"
```
**Test a function after requiring:**
```bash
clj-nrepl-eval -p <PORT> "(ns/my-function arg1 arg2)"
```
**Check if a file compiles:**
```bash
clj-nrepl-eval -p <PORT> "(require 'my.namespace :reload)"
```
**Multiple expressions:**
```bash
clj-nrepl-eval -p <PORT> "(def x 10) (* x 2) (+ x 5)"
```
**Complex multiline code (using heredoc):**
```bash
clj-nrepl-eval -p <PORT> <<'EOF'
(def x 10)
(* x 2)
(+ x 5)
EOF
```
*Note: Heredoc syntax may require permission approval.*
**With custom timeout (in milliseconds):**
```bash
clj-nrepl-eval -p <PORT> --timeout 5000 "(long-running-fn)"
```
**Reset the session (clears all state):**
```bash
clj-nrepl-eval -p <PORT> --reset-session
clj-nrepl-eval -p <PORT> --reset-session "(def x 1)"
```
## Available Options
- `-p, --port PORT` - nREPL port (required)
- `-H, --host HOST` - nREPL host (default: 127.0.0.1)
- `-t, --timeout MILLISECONDS` - Timeout (default: 120000 = 2 minutes)
- `-r, --reset-session` - Reset the persistent nREPL session
- `-c, --connected-ports` - List previously connected nREPL sessions
- `-d, --discover-ports` - Discover nREPL servers in current directory
- `-h, --help` - Show help message
## Important Notes
- **Prefer command-line arguments:** Pass code as quoted strings: `clj-nrepl-eval -p <PORT> "(+ 1 2 3)"` - works with existing permissions
- **Heredoc for complex code:** Use heredoc (`<<'EOF' ... EOF`) for truly multiline code, but note it may require permission approval
- **Sessions persist:** State (vars, namespaces, loaded libraries) persists across invocations until the nREPL server restarts or `--reset-session` is used
- **Automatic delimiter repair:** The tool automatically repairs missing or mismatched parentheses
- **Always use :reload:** When requiring namespaces, use `:reload` to pick up recent changes
- **Default timeout:** 2 minutes (120000ms) - increase for long-running operations
- **Input precedence:** Command-line arguments take precedence over stdin
## Typical Workflow
1. Discover nREPL servers: `clj-nrepl-eval --discover-ports`
2. Use **AskUserQuestion** tool to prompt user to select a port
3. Require namespace:
```bash
clj-nrepl-eval -p <PORT> "(require '[my.ns :as ns] :reload)"
```
4. Test function:
```bash
clj-nrepl-eval -p <PORT> "(ns/my-fn ...)"
```
5. Iterate: Make changes, re-require with `:reload`, test again

View File

@@ -1,834 +0,0 @@
---
name: emotion-migrate
description: Migrate Emotion styled-components to Mantine components with style props and CSS modules. Use when converting .styled.tsx files or removing @emotion imports from components.
---
# Emotion → Mantine + CSS Modules Migration Skill
Migrate Emotion styled-components (`@emotion/styled`, `@emotion/react`) to Mantine layout components with style props and CSS modules. The goal is zero Emotion imports, zero inline styles, and maximum use of design system tokens.
## Priority Order (Strict)
1. **Mantine components + style props** — `Box`, `Flex`, `Stack`, `Group`, `Text`, `Title`, `Card`. This is the DEFAULT. Every CSS property must be checked against style props FIRST.
2. **CSS modules** (`.module.css`) — ONLY for properties that Mantine style props genuinely cannot express: pseudo-selectors (`:hover`, `:focus`, `::before`), `box-shadow`, `border` shorthand, `animation`/`@keyframes`, complex selectors, `cursor`, `pointer-events`, `overflow`, `text-overflow`, `white-space`, `transition`.
3. **Inline styles ONLY for dynamic values** — `style={{ }}` is allowed only for truly dynamic runtime values (e.g., computed widths, positions, data-driven colors). All static styles must use Mantine props or CSS modules.
### Mantine-First Decision Gate (CRITICAL)
For EACH styled component, go through every CSS property and ask: "Can this be a Mantine style prop?" If yes → style prop. If no → CSS module. Do NOT dump an entire component into a CSS module just because one property needs it — split them.
**Properties that ARE style props** (use these, not CSS modules):
- `display` → `display` prop
- `color` → `c` prop (`c="brand"`, `c="text-primary"`)
- `background-color` → `bg` prop (`bg="background-primary"`)
- `font-size` → `fz` prop (`fz="md"`)
- `font-weight` → `fw` prop (`fw="bold"`)
- `line-height` → `lh` prop (`lh="md"`)
- `text-align` → `ta` prop (`ta="center"`)
- `padding` (all variants) → `p`, `px`, `py`, `pt`, `pb`, `pl`, `pr`
- `margin` (all variants) → `m`, `mx`, `my`, `mt`, `mb`, `ml`, `mr`
- `width` → `w`, `min-width` → `miw`, `max-width` → `maw`
- `height` → `h`, `min-height` → `mih`, `max-height` → `mah`
- `flex` → `flex` prop (`flex="0 0 auto"`, `flex={1}`)
- `gap` → `gap` prop (on Flex/Stack/Group)
- `align-items` → `align` prop (on Flex/Stack/Group)
- `justify-content` → `justify` prop (on Flex/Stack/Group)
- `flex-direction` → `direction` prop (on Flex)
- `flex-wrap` → `wrap` prop (on Flex)
- `position` → `pos` prop
- `top/right/bottom/left` → `top`, `right`, `bottom`, `left` props
- `opacity` → `opacity` prop
**Properties that NEED CSS modules** (no style prop equivalent):
- `:hover`, `:focus`, `:active`, `::before`, `::after` (pseudo-selectors)
- `box-shadow`, `border` (shorthand with color), `outline`
- `cursor`, `pointer-events`
- `overflow`, `text-overflow`, `white-space`
- `animation`, `transition`, `transform`
- `@media` queries (UNLESS it's simple responsive spacing/sizing — then use responsive syntax: `p={{ base: "md", lg: "xl" }}`)
**Hybrid approach** — when a component needs BOTH, put style props on the Mantine component AND add a CSS module class for the rest:
```tsx
<Flex
className={S.root} /* for :hover, box-shadow, border */
align="center" /* style prop */
gap="sm" /* style prop */
p="md" /* style prop */
bg="background-primary" /* style prop */
>
```
## CSS Module Conventions (Strict)
### Class Naming: camelCase
All CSS module class names MUST use **camelCase**. This is the dominant convention across the codebase (~830 camelCase vs ~620 PascalCase classes), used consistently in Mantine UI components, and matches standard CSS module conventions.
```css
/* CORRECT */
.root {
}
.settingsSection {
}
.dragHandle {
}
.closeIcon {
}
/* WRONG — do not use PascalCase or kebab-case */
.ItemRoot {
}
.settings-section {
}
```
Modifier/state classes also use camelCase:
```css
.selected {
}
.disabled {
}
.interactive {
}
.draggable {
}
```
### No Cascading — Direct Class Assignment
Cascading selectors are **discouraged**. Instead of styling through parent-child relationships, assign a class directly to the element that needs styling.
```css
/* WRONG — cascading/descendant selectors */
.root > input {
}
.root .label {
}
.container > div > span {
}
/* CORRECT — direct class on the target element */
.input {
}
.label {
}
.title {
}
```
The only acceptable nesting patterns are:
- **Pseudo-selectors on the same element**: `.item { &:hover { } }`
- **Modifier composition**: `.item { &.selected { } }`
- **Hover-reveal patterns** where a parent hover affects a child: `.root:hover .showOnHover { opacity: 1; }` — but only when structurally necessary (the child has no way to know about the parent's hover state)
### Import Alias
Always import the CSS module as `S`:
```tsx
import S from "./ComponentName.module.css";
```
## Step-by-Step Migration Process
### Step 1: Read and Understand
Read the `.styled.tsx` file AND every component that imports from it. Understand:
- Which styled components are used and where
- Which props drive dynamic styles
- Which styles are static vs conditional
- Which styles can map directly to Mantine style props
### Step 2: Classify Each Styled Component
For each styled component, apply the Mantine-First Decision Gate above. Then determine the migration target:
| Emotion Pattern | Migration Target |
| ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `styled.div` with only layout/spacing/color | `Box`, `Flex`, `Stack`, or `Group` with style props. **NO CSS module needed.** |
| `styled.div` with flexbox column | `Stack` component with style props |
| `styled.div` with flexbox row | `Flex` or `Group` component with style props |
| `styled.span` / `styled.p` with color/weight/size | **`Text component="span"` with style props** (`c`, `fw`, `fz`). NO CSS module. |
| `styled.div` with hover/focus/pseudo-selectors | **Hybrid**: Mantine component with style props for expressible properties + CSS module class for pseudo-selectors only |
| `styled.div` with media queries (simple spacing/sizing) | **Responsive style props**: `p={{ base: "md", lg: "xl" }}`. NO CSS module. |
| `styled.div` with media queries (complex/non-spacing) | CSS module for the media query parts, style props for the rest |
| `styled.div` with animations/keyframes | CSS module for animation, style props for layout |
| `styled(SomeComponent)` with only color/spacing/flex | **Wrap in Mantine component** with style props: `<Box c="brand" flex="0 0 auto"><Icon /></Box>`, or pass style props if the component accepts them |
| `styled(SomeComponent)` with pseudo-selectors/complex styles | CSS module `className` on the component |
| Dynamic props `styled.div<{ isActive: boolean }>` | Mantine style props for simple toggles (`c={active ? "brand" : "text-primary"}`), `cx()` with CSS module classes for complex state combinations involving pseudo-selectors |
### Step 3: Create CSS Module (if needed)
Create `ComponentName.module.css` alongside the component file:
```css
/* Use design system tokens — NEVER raw color/spacing values */
.root {
border: 1px solid var(--mb-color-border);
border-radius: var(--mantine-radius-md);
background-color: var(--mb-color-background-primary);
}
/* Conditional states as separate classes, combined with cx() */
.active {
background-color: var(--mb-color-brand);
color: var(--mb-color-text-primary-inverse);
}
.disabled {
color: var(--mb-color-text-tertiary);
pointer-events: none;
}
/* Hover/focus/pseudo-selectors — nest with & */
.interactive {
cursor: pointer;
&:hover {
color: var(--mb-color-brand);
background-color: var(--mb-color-background-hover);
}
}
/* Hover-reveal: acceptable parent→child nesting */
.root:hover .showOnHover {
opacity: 1;
}
/* Responsive styles */
@media (--breakpoint-min-md) {
.root {
padding: var(--mantine-spacing-lg);
}
}
```
### Step 4: Update the Component TSX
```tsx
import cx from "classnames";
import CS from "metabase/css/core/index.css";
import { Box, Flex, Group, Stack, Text } from "metabase/ui";
import S from "./ComponentName.module.css";
// Dynamic props → cx() with conditional classes
<Flex
className={cx(S.root, {
[S.active]: isActive,
[S.disabled]: disabled,
})}
align="center"
gap="sm"
p="md"
w="100%"
>
```
### Step 5: Delete the `.styled.tsx` File
Remove the old styled file entirely. Remove all imports of it from other files.
### Step 6: Verify
- Confirm zero `@emotion/styled` or `@emotion/react` imports remain in the migrated files
- Confirm no static inline styles (dynamic runtime values are fine)
- Confirm all colors use tokens, not raw hex/rgb values
## Design System Token Reference
### Mantine Style Props (use directly on components)
**Spacing** (`p`, `px`, `py`, `pt`, `pb`, `pl`, `pr`, `m`, `mx`, `my`, `mt`, `mb`, `ml`, `mr`):
- `"xs"` = 4px, `"sm"` = 8px, `"md"` = 16px, `"lg"` = 24px, `"xl"` = 32px
- Custom: `rem(48)` for non-standard values (import `rem` from `metabase/ui`)
**Dimensions** (`w`, `h`, `maw`, `mah`, `miw`, `mih`):
- `"100%"`, `"100vh"`, `rem(400)`, etc.
**Colors** (`c`, `bg`):
- Text: `"text-primary"`, `"text-secondary"`, `"text-tertiary"`
- Background: `"background-primary"`, `"background-secondary"`, `"background-hover"`
- Brand: `"brand"`, `"error"`, `"success"`, `"warning"`
**Typography** (`fz`, `fw`, `lh`, `ta`, `ff`):
- Font size: `"xs"` = 11px, `"sm"` = 12px, `"md"` = 14px, `"lg"` = 17px, `"xl"` = 21px
- Font weight: `"bold"`, `"normal"`, or numeric `700`
- Line height: `"xs"` = 100%, `"sm"` = 115%, `"md"` = 122%, `"lg"` = 138%, `"xl"` = 150%
- Text align: `"center"`, `"left"`, `"right"`
**Flexbox** (`align`, `justify`, `gap`, `direction`, `wrap`, `flex`):
- `align="center"`, `justify="space-between"`, `gap="sm"`, `direction="column"`, `wrap="nowrap"`
- `flex={1}`, `flex="0 0 auto"`
**Other**: `pos` (position), `display`
**Responsive syntax**: `px={{ base: "md", md: "lg", lg: rem(48) }}`
### CSS Variable Tokens (use in `.module.css` files)
**Colors** — `var(--mb-color-<name>)`:
- `--mb-color-text-primary`, `--mb-color-text-secondary`, `--mb-color-text-tertiary`
- `--mb-color-background-primary`, `--mb-color-background-secondary`, `--mb-color-background-hover`
- `--mb-color-border`, `--mb-color-border-strong`, `--mb-color-border-subtle`
- `--mb-color-brand`, `--mb-color-brand-hover`
- `--mb-color-error`, `--mb-color-success`, `--mb-color-warning`
- `--mb-color-shadow`, `--mb-color-focus`
- `--mb-color-accent0` through `--mb-color-accent7`
**Mantine spacing** — `var(--mantine-spacing-<size>)`:
- `--mantine-spacing-xs` (4px), `--mantine-spacing-sm` (8px), `--mantine-spacing-md` (16px), `--mantine-spacing-lg` (24px), `--mantine-spacing-xl` (32px)
**Mantine radius** — `var(--mantine-radius-<size>)`:
- `--mantine-radius-xs` (4px), `--mantine-radius-sm` (6px), `--mantine-radius-md` (8px), `--mantine-radius-xl` (40px)
**Mantine font sizes** — `var(--mantine-font-size-<size>)`:
- `--mantine-font-size-xs` (11px), `--mantine-font-size-sm` (12px), `--mantine-font-size-md` (14px), `--mantine-font-size-lg` (17px), `--mantine-font-size-xl` (21px)
**Breakpoints** (in `.module.css` files):
- `@media (--breakpoint-min-sm)` (40em / 640px)
- `@media (--breakpoint-min-md)` (60em / 960px)
- `@media (--breakpoint-min-lg)` (80em / 1280px)
- `@media (--breakpoint-min-xl)` (120em / 1920px)
- Also available: `--breakpoint-max-*` variants
### Snap Hardcoded Literals to Nearest Design Token (CRITICAL)
When migrating, **never carry over hardcoded `rem`/`px` values** from the original Emotion code. Instead, snap them to the nearest design system token. The original values were often arbitrary — the migration is an opportunity to align with the design system.
**Spacing** — snap to the nearest Mantine spacing token:
| Hardcoded value | Nearest token | Style prop | CSS variable |
| --------------------------------- | ------------- | ------------ | ------------------------------ |
| `0.125rem` (2px) | `2px` | `2` (number) | `2px` (keep literal, no token) |
| `0.2rem` (3.2px), `0.25rem` (4px) | **xs** (4px) | `"xs"` | `var(--mantine-spacing-xs)` |
| `0.5rem` (8px) | **sm** (8px) | `"sm"` | `var(--mantine-spacing-sm)` |
| `0.75rem` (12px) | between sm/md | `rem(12)` | `0.75rem` (no exact token) |
| `1rem` (16px) | **md** (16px) | `"md"` | `var(--mantine-spacing-md)` |
| `1.5rem` (24px) | **lg** (24px) | `"lg"` | `var(--mantine-spacing-lg)` |
| `2rem` (32px) | **xl** (32px) | `"xl"` | `var(--mantine-spacing-xl)` |
**Border radius** — snap to the nearest Mantine radius token:
| Hardcoded value | Nearest token | CSS variable |
| ---------------- | ----------------------------- | -------------------------- |
| `0.25rem` (4px) | **xs** (4px) | `var(--mantine-radius-xs)` |
| `0.375rem` (6px) | **sm** (6px) | `var(--mantine-radius-sm)` |
| `0.5rem` (8px) | **md** (8px) | `var(--mantine-radius-md)` |
| `1rem`+ (16px+) | **xl** (40px) or keep literal | `var(--mantine-radius-xl)` |
**Font sizes** — snap to the nearest Mantine font size token:
| Hardcoded value | Nearest token | Style prop | CSS variable |
| -------------------------------- | ------------- | ---------- | ----------------------------- |
| `0.6875rem` (11px) | **xs** (11px) | `fz="xs"` | `var(--mantine-font-size-xs)` |
| `0.75rem` (12px) | **sm** (12px) | `fz="sm"` | `var(--mantine-font-size-sm)` |
| `0.875rem` (14px), `1rem` (16px) | **md** (14px) | `fz="md"` | `var(--mantine-font-size-md)` |
| `1.063rem` (17px) | **lg** (17px) | `fz="lg"` | `var(--mantine-font-size-lg)` |
| `1.3rem` (21px) | **xl** (21px) | `fz="xl"` | `var(--mantine-font-size-xl)` |
**Rules:**
- If the hardcoded value is within ~2px of a token, use the token
- If it falls exactly between two tokens, prefer the smaller one (tighter is safer)
- If no token is close (e.g., `48px` spacing), use `rem(48)` for style props or the literal value in CSS modules
- This applies everywhere: style props, CSS module values, Icon `size` props, etc.
## Common Migration Patterns
### Pattern 1: Static Layout Container → Mantine Component
**Before:**
```tsx
// Component.styled.tsx
export const Container = styled.div`
display: flex;
align-items: center;
gap: 0.5rem;
padding: 1rem;
width: 100%;
`;
```
**After:**
```tsx
<Flex align="center" gap="sm" p="md" w="100%">
```
### Pattern 2: Vertical Stack → Stack Component
**Before:**
```tsx
export const Wrapper = styled.div`
display: flex;
flex-direction: column;
gap: 1.5rem;
padding: 2rem;
`;
```
**After:**
```tsx
<Stack gap="lg" p="xl">
```
### Pattern 3: Dynamic Props → cx() with CSS Module Classes
**Before:**
```tsx
export const Item = styled.div<{ isSelected: boolean; disabled: boolean }>`
color: ${(props) =>
props.disabled ? color("text-tertiary") : color("text-primary")};
background-color: ${(props) =>
props.isSelected ? color("brand") : "transparent"};
cursor: ${(props) => (props.disabled ? "default" : "pointer")};
&:hover {
color: ${(props) => !props.disabled && color("brand")};
}
`;
```
**After (CSS module):**
```css
/* Item.module.css */
.itemRoot {
color: var(--mb-color-text-primary);
cursor: pointer;
&:hover {
color: var(--mb-color-brand);
}
}
.selected {
background-color: var(--mb-color-brand);
}
.disabled {
color: var(--mb-color-text-tertiary);
cursor: default;
&:hover {
color: var(--mb-color-text-tertiary);
}
}
```
**After (TSX):**
```tsx
<Box
className={cx(S.itemRoot, {
[S.selected]: isSelected,
[S.disabled]: disabled,
})}
>
```
### Pattern 4: Extending a Component → Style Props First, CSS Module Only If Needed
When a styled component wraps another component, first check if the styles can be expressed as style props on a Mantine wrapper or on the component itself. Only use a CSS module when properties genuinely need it.
**Before:**
```tsx
export const CardIcon = styled(Icon)`
display: block;
flex: 0 0 auto;
color: var(--mb-color-brand);
`;
export const CardTitle = styled(Ellipsified)`
color: var(--mb-color-text-primary);
font-size: 1rem;
font-weight: bold;
margin-left: 1rem;
`;
```
**After — style props on Mantine wrapper (preferred when ALL properties are expressible):**
```tsx
<Box display="block" flex="0 0 auto" c="brand">
<Icon {...icon} />
</Box>
<Box c="text-primary" fz="md" fw="bold" ml="md">
<Ellipsified>{title}</Ellipsified>
</Box>
```
**After — CSS module (use only when component has pseudo-selectors or non-expressible styles):**
```css
.icon {
color: var(--mb-color-brand);
width: 1.5rem;
height: 1.5rem;
cursor: pointer;
&:hover {
color: var(--mb-color-brand-hover);
}
}
```
```tsx
<Icon className={S.icon} name="warning" />
```
### Pattern 4b: `styled.span` / `styled.p` with Text Styles → `Text` Component
**Before:**
```tsx
export const Label = styled.span`
color: var(--mb-color-text-secondary);
font-weight: bold;
`;
export const Title = styled.span`
color: var(--mb-color-text-primary);
font-size: 1rem;
font-weight: bold;
margin-left: 0.5rem;
`;
```
**After — `Text` component with style props (NO CSS module needed):**
```tsx
<Text component="span" c="text-secondary" fw="bold">
{label}
</Text>
<Text component="span" c="text-primary" fz="md" fw="bold" ml="sm">
{title}
</Text>
```
`Text` renders as `<p>` by default. Use `component="span"` to render inline. All color, typography, and spacing props work directly — no CSS module needed for pure text styling.
### Pattern 5: Keyframes Animation → CSS Module
**Before:**
```tsx
const spin = keyframes`
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
`;
export const Spinner = styled.div`
animation: ${spin} 1s infinite linear;
`;
```
**After (CSS module):**
```css
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.spinner {
animation: spin 1s infinite linear;
}
```
**After (TSX):**
```tsx
<Box className={S.spinner} />
```
### Pattern 6: color() Function → CSS Variables
| Emotion (JS) | CSS Module | Mantine Style Prop |
| ----------------------- | ------------------------------------------------------------ | --------------------------- |
| `color("brand")` | `var(--mb-color-brand)` | `c="brand"` or `bg="brand"` |
| `color("text-primary")` | `var(--mb-color-text-primary)` | `c="text-primary"` |
| `color("border")` | `var(--mb-color-border)` | N/A (use CSS module) |
| `alpha("brand", 0.2)` | `color-mix(in srgb, var(--mb-color-brand), transparent 80%)` | N/A (use CSS module) |
### Pattern 7: Responsive Spacing/Sizing → Responsive Style Props (NOT CSS Media Queries)
When a styled component only changes spacing, sizing, or other style-prop-expressible values at breakpoints, use Mantine's responsive syntax instead of CSS module media queries.
**Before:**
```tsx
export const CaptionRoot = styled.div`
margin-bottom: 1.5rem;
${breakpointMinExtraLarge} {
margin-bottom: 2rem;
}
`;
```
**After — responsive style prop (NO CSS module needed):**
```tsx
<Flex mb={{ base: "lg", xl: "xl" }}>
```
Breakpoint keys: `base` (default), `xs` (40em), `sm` (48em), `md` (60em), `lg` (80em), `xl` (120em).
Only use CSS module `@media` queries when the responsive change involves non-style-prop properties (e.g., `box-shadow`, `border`, `cursor` changes at breakpoints).
### Pattern 8: Dynamic Computed Styles → Inline Styles
Inline styles are allowed **only** for truly dynamic values computed at runtime (e.g., widths, positions, colors from data). Everything else must use Mantine style props or CSS modules.
**Before:**
```tsx
export const Bar = styled.div<{ width: number }>`
width: ${(props) => props.width}%;
`;
```
**After:**
```tsx
<Box style={{ width: `${width}%` }} />
```
### Pattern 9: Core CSS Utility Classes (Discouraged)
**Do NOT introduce new `CS` utility class usage.** Core CSS utilities (`CS` from `metabase/css/core/index.css`) are legacy and discouraged for new code. Prefer Mantine style props or CSS modules instead.
If existing code already uses `CS` classes and you're not migrating that specific code, leave them alone. But when migrating Emotion → Mantine, replace with the proper alternative:
| Instead of `CS.*` | Use |
| ------------------- | ------------------------------------------------------- |
| `CS.overflowHidden` | CSS module: `overflow: hidden` |
| `CS.cursorPointer` | CSS module: `cursor: pointer` |
| `CS.flex1` | Style prop: `flex={1}` |
| `CS.flexNoShrink` | Style prop: `flex="0 0 auto"` |
| `CS.textBrandHover` | CSS module: `&:hover { color: var(--mb-color-brand); }` |
### Pattern 10: Shared Emotion Styles Across Files → Shared CSS Module + cx()
When Emotion exports a shared `css` block (like `animationStyles`) imported by many files, create ONE CSS module with the shared keyframe and a reusable class, then compose via `cx()`.
**Before (Emotion — shared animation used by 13+ skeleton files):**
```tsx
// ChartSkeleton.styled.tsx — defines shared animation
const fadingKeyframes = keyframes`
0% { opacity: 0.0625; }
50% { opacity: 0.125; }
100% { opacity: 0.0625; }
`;
export const animationStyles = css`
opacity: 0.1;
animation: ${fadingKeyframes} 1.5s infinite;
`;
// AreaSkeleton.styled.tsx — consumes it
import { animationStyles } from ".../ChartSkeleton.styled";
export const SkeletonImage = styled.svg`
${animationStyles};
flex: 1 1 0;
margin-top: 1rem;
border-bottom: 1px solid currentColor;
`;
// BarSkeleton.styled.tsx — also consumes it
import { animationStyles } from ".../ChartSkeleton.styled";
export const SkeletonImage = styled.svg`
${animationStyles};
flex: 1 1 0;
margin-top: 1rem;
`;
```
**After — shared CSS module:**
```css
/* ChartSkeleton.module.css */
@keyframes fading {
0% {
opacity: 0.0625;
}
50% {
opacity: 0.125;
}
100% {
opacity: 0.0625;
}
}
.animated {
opacity: 0.1;
animation: fading 1.5s infinite;
}
```
**After — per-component CSS modules with own styles only:**
```css
/* AreaSkeleton.module.css */
.skeletonImage {
flex: 1 1 0;
margin-top: 1rem;
border-bottom: 1px solid currentColor;
}
```
```css
/* BarSkeleton.module.css */
.skeletonImage {
flex: 1 1 0;
margin-top: 1rem;
}
```
**After — component TSX uses cx() to compose:**
```tsx
// AreaSkeleton.tsx
import cx from "classnames";
import ChartSkeletonS from "../ChartSkeleton/ChartSkeleton.module.css";
import S from "./AreaSkeleton.module.css";
const AreaSkeleton = (): JSX.Element => {
return (
<svg
className={cx(ChartSkeletonS.animated, S.skeletonImage)}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 371 113"
preserveAspectRatio="none"
>
<path d="..." fill="currentColor" />
</svg>
);
};
```
The shared module owns the `@keyframes` and the `.animated` class. Each consumer composes it with its own module class via `cx()`. No duplication of the keyframe definition.
## Import Template
```tsx
import cx from "classnames"; // only if needed for conditional classes
import { Box, Flex, Group, Stack, Text, rem } from "metabase/ui";
import S from "./ComponentName.module.css"; // only if CSS module is needed
```
## Checklist Before Finishing
- [ ] **MANTINE-FIRST CHECK**: Every CSS property that has a style prop equivalent (`c`, `bg`, `p`, `m`, `fw`, `fz`, `flex`, `gap`, `align`, `w`, `h`, etc.) is expressed as a style prop, NOT in a CSS module
- [ ] `styled.span`/`styled.p` with only color/weight/size are replaced with `Text component="span"` + style props, NOT CSS module classes
- [ ] `styled.div` with only layout props are replaced with `Flex`/`Stack`/`Group`/`Box` + style props, NOT CSS module classes
- [ ] Responsive spacing/sizing uses responsive style props (`mb={{ base: "lg", xl: "xl" }}`), NOT CSS module `@media` queries
- [ ] CSS modules are used ONLY for: pseudo-selectors, box-shadow, border, cursor, overflow, animation, transition, transform, or complex selectors
- [ ] All `@emotion/styled` and `@emotion/react` imports removed from migrated files
- [ ] The `.styled.tsx` file is deleted
- [ ] All imports of the deleted styled file are updated
- [ ] No static inline styles — `style={{ }}` used only for truly dynamic runtime values
- [ ] All colors use design tokens (`c="brand"`, `var(--mb-color-brand)`), not raw hex/rgb
- [ ] All spacing uses design tokens (`p="md"`, `var(--mantine-spacing-md)`), not arbitrary px values — hardcoded `rem`/`px` literals snapped to the nearest token (see mapping table above)
- [ ] All border-radius values use radius tokens (`var(--mantine-radius-md)`), not hardcoded `0.5rem`
- [ ] All font sizes use font-size tokens (`fz="md"`, `var(--mantine-font-size-md)`), not hardcoded `1rem`
- [ ] Layout uses Mantine components (`Flex`, `Stack`, `Group`, `Box`, `Text`) not raw divs/spans with CSS
- [ ] All CSS module class names use camelCase
- [ ] No cascading/descendant selectors targeting raw elements — use direct class assignment instead
- [ ] Component renders identically to the original (visually verify if possible)
## Visual Verification with Screenshots (Optional — Only When Explicitly Asked)
When the user explicitly asks to create before/after screenshots, use the Playwright MCP tools to capture them. This is NOT done by default — only when requested.
Screenshots must be taken in **both light and dark mode** to verify token usage is correct in both themes.
### Switching Color Scheme via API
Toggle between light and dark mode using the Metabase settings API. Use Playwright's `browser_evaluate` or `browser_navigate` with fetch:
```js
// Switch to dark mode
await fetch("/api/setting/color-scheme", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ value: "dark" }),
});
// Switch to light mode
await fetch("/api/setting/color-scheme", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ value: "light" }),
});
```
After switching, reload the page for the theme to take effect.
### Process
For each state (**after** = migrated code, **before** = stashed original), capture screenshots in both themes at both viewport widths. This produces **8 screenshots total**.
1. **Take "after" screenshots first** (migrated code is already in place):
- Navigate to the page that renders the migrated components (`browser_navigate`)
- Wait for content to load (`browser_wait_for` with key text, or `textGone: "Loading..."`)
- Close the sidebar if it overlaps content on narrow viewports (`browser_click` the toggle button)
- **Light mode** (set `color-scheme` to `"light"` via API, reload):
- Desktop (1280x900): `after-light-desktop.png`
- Narrow (640x900), close sidebar: `after-light-narrow.png`
- **Dark mode** (set `color-scheme` to `"dark"` via API, reload):
- Desktop (1280x900): `after-dark-desktop.png`
- Narrow (640x900), close sidebar: `after-dark-narrow.png`
2. **Stash changes to capture "before" screenshots**:
- Run `git stash --include-untracked` to temporarily revert to the Emotion version
- Repeat the same 4 screenshots with `before-` prefix:
- `before-light-desktop.png`, `before-light-narrow.png`
- `before-dark-desktop.png`, `before-dark-narrow.png`
- Run `git stash pop` to restore the migrated code
3. **Restore the user's original color scheme** (set back to `"auto"` or whatever it was before).
4. **Display all 8 screenshots** using the `Read` tool so the user can visually compare before/after in both themes at both viewport sizes.
### Key Details
- Save screenshots in the repo root (they will be untracked — user can delete after review)
- The dev server must be running (typically `http://localhost:3000`)
- Use `browser_snapshot` to find element refs when you need to click buttons (e.g., sidebar toggle)
- The greeting text on the home page changes randomly on each load — this is expected, not a regression
- If the page being tested is not the home page, navigate to the correct URL that exercises the migrated components
- Dark mode screenshots are critical for verifying that CSS variable tokens (`var(--mb-color-*)`) are used correctly — hardcoded colors will look wrong in dark mode

View File

@@ -176,10 +176,8 @@
clojure.core.async/to-chan!
clojure.core.async/to-chan!!
metabase.channel.core/send!
metabase.warehouses.models.database/assert-not-h2!
metabase.driver.sql-jdbc.execute/execute-prepared-statement!
metabase.notification.models/create-notification!
metabase.oauth-server.core/reset-provider!
metabase.pulse.send/send-pulse!
metabase-enterprise.transforms-python.python-runner-test/execute!
;; Workspace isolation functions are safe in parallel tests because they operate on
@@ -479,7 +477,6 @@
metabase.query-processor.setup/with-qp-setup clojure.core/let
metabase.search.api-test/do-test-users clojure.core/let
metabase.settings.core/define-multi-setting clojure.core/def
metabase.api-scope.core/defscope clj-kondo.lint-as/def-catch-all
metabase.settings.core/defsetting clj-kondo.lint-as/def-catch-all
metabase.settings.models.setting.multi-setting/define-multi-setting clojure.core/def
metabase.settings.models.setting/defsetting clj-kondo.lint-as/def-catch-all
@@ -555,7 +552,6 @@
metabase-enterprise.cache.config-test/with-temp-persist-models hooks.common/with-seven-bindings
metabase-enterprise.dependencies.api-test/with-dependents-test! hooks.common/with-two-bindings
metabase-enterprise.metabot-v3.tools.dependencies-test/with-dependent-transforms! hooks.common/with-two-bindings
metabase-enterprise.metabot.tools.dependencies-test/with-dependent-transforms! hooks.common/with-two-bindings
metabase-enterprise.semantic-search.db.connection/with-migrate-tx hooks.common/let-one-with-optional-value
metabase-enterprise.serialization.api-test/with-serialization-test-data! hooks.common/with-three-bindings
metabase-enterprise.serialization.test-util/with-temp-dpc hooks.toucan2.tools.with-temp/with-temp
@@ -797,7 +793,7 @@
:private-call {:level :off}
:metabase/defsetting-must-specify-export {:level :off}
:metabase/defsetting-namespace {:level :off}
:metabase/test-helpers-use-non-thread-safe-functions {:level :warning} ; more config in `.clj-kondo/config/test-helpers/config.edn`
:metabase/test-helpers-use-non-thread-safe-functions {:level :warning} ; more config in `.clj-kondo/config/test-helpers/config.edn
:discouraged-var
{metabase.driver/database-supports? {:level :off}

File diff suppressed because it is too large Load Diff

View File

@@ -110,7 +110,6 @@
metabase.settings.models.setting-test/test-user-local-allowed-setting!
metabase.settings.models.setting-test/test-user-local-only-setting!
metabase.settings.models.setting.cache/restore-cache!
metabase.settings.models.setting/log-deprecated-env-var-usage!
metabase.settings.models.setting/set!
metabase.settings.models.setting/validate-settings-formatting!
metabase.setup.core/create-token!

View File

@@ -7,7 +7,9 @@ inputs:
output-name:
required: true
default: test
role-to-assume:
aws-access-key-id:
required: true
aws-secret-access-key:
required: true
aws-region:
required: true
@@ -28,7 +30,8 @@ runs:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ inputs.role-to-assume }}
aws-access-key-id: ${{ inputs.aws-access-key-id }}
aws-secret-access-key: ${{ inputs.aws-secret-access-key }}
aws-region: ${{ inputs.aws-region }}
- name: zip test results
env:
@@ -47,18 +50,13 @@ runs:
aws s3 cp ${OUTPUT_FILE}.zip s3://$BUCKET/$DATE/$GITHUB_RUN_ID/$GITHUB_RUN_ATTEMPT/
- name: Upload results to Trunk
# Important!
# 1. This step must always run because it controls job's exit code.
# 2. There's no point in running this outside the organization
if: always() && github.repository_owner == 'metabase'
if: always() # Important! This step must always run because it controls job's exit code.
uses: trunk-io/analytics-uploader@main
env:
TRUNK_REPO_URL: git@github.com:metabase/metabase.git
with:
junit-paths: ${{ inputs.input-path }}
variant: ${{ inputs.variant || inputs.output-name }}
org-slug: metabase
dry-run: ${{ (github.event_name == 'pull_request' && github.event.pull_request.draft == true) || github.repository != 'metabase/metabase' }} # quarantine, but do not upload results
dry-run: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == true }} # quarantine, but do not upload results
token: ${{ inputs.trunk-api-token }}
use-cache: true
previous-step-outcome: ${{ inputs.previous-step-outcome }}

View File

@@ -200,10 +200,6 @@ cljs:
- ".github/workflows/cljs.yml"
- "shadow-cljs.edn"
serialization_baseline:
- ".github/workflows/serialization.yml"
- "test_resources/serialization_baseline/**"
openapi:
- ".github/workflows/openapi.yml"
- "src/metabase/api/**"

View File

@@ -3,7 +3,7 @@ const { buildMatrix } = require("./build-e2e-matrix");
describe("buildMatrix", () => {
const options = {
java: "11",
defaultRunner: "${{ vars.DEFAULT_RUNNER_KEY }}",
defaultRunner: "ubuntu-22.04",
};
const testBuildMatrix = (entry, chunks) =>
buildMatrix(options, entry, chunks);

View File

@@ -19,7 +19,7 @@ while [[ $# -gt 0 ]]; do
done
echo "Cloning python-runner repository..."
git clone --depth 1 https://${METABASE_AUTOMATION_USER_TOKEN}@github.com/metabase/python-runner-container.git python-runner
git clone --depth 1 -b extensible-resource-schema https://${METABASE_AUTOMATION_USER_TOKEN}@github.com/metabase/python-runner-container.git python-runner
if [ "$SKIP_START" = false ]; then
echo "Starting python-runner..."

9
.github/team.json vendored
View File

@@ -1,13 +1,13 @@
{
"teams": [
{
"name": "Querying Platform",
"label": ".Team/QueryingPlatform",
"name": "Querying",
"label": ".Team/Querying",
"members": [
"bshepherdson",
"metamben",
"rileythomp",
"camsaul"
"camsual"
]
},
{
@@ -106,8 +106,7 @@
"kamilmielnik",
"stasgavrylov",
"uladzimirdev",
"egorgrushin",
"metatyb"
"egorgrushin"
]
},
{

View File

@@ -14,7 +14,7 @@ concurrency:
jobs:
be-tests-mariadb:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 40
strategy:
fail-fast: false
@@ -22,12 +22,12 @@ jobs:
version:
- name: MariaDB 10.6
junit-name: be-tests-mariadb-10-6-ee
image: metabase/mariadb:10.6 # https://github.com/metabase/metabase-mariadb-docker-image
image: circleci/mariadb:10.6
env:
enable-ssl-tests: 'false'
- name: MariaDB Latest
junit-name: be-tests-mariadb-latest-ee
image: mariadb:latest
image: circleci/mariadb:latest
env:
enable-ssl-tests: 'false'
job:
@@ -57,8 +57,8 @@ jobs:
ports:
- "3306:3306"
env:
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: true
MARIADB_DATABASE: mb_test
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: circle_test
env:
# Only run old migrations tests on pushes to master or release branches. All other branches should skip tests
# with the tag `mb/old-migrations-test`. `__ADDITIONAL_EXCLUDED_TAG__` is not used anywhere outside of splicing
@@ -81,7 +81,7 @@ jobs:
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
#
@@ -120,14 +120,15 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-mysql:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 40
strategy:
fail-fast: false
@@ -135,7 +136,7 @@ jobs:
version:
- name: MySQL 8.4
junit-name: be-tests-mysql-8-4-ee
image: mysql:8.4
image: cimg/mysql:8.4
env:
enable-ssl-tests: 'false'
enable-aws-iam-tests: 'false'
@@ -173,7 +174,7 @@ jobs:
- "3306:3306"
env:
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: mb_test
MYSQL_DATABASE: circle_test
env:
# Only run old migrations tests on pushes to master or release branches. All other branches should skip tests
# with the tag `mb/old-migrations-test`. `__ADDITIONAL_EXCLUDED_TAG__` is not used anywhere outside of splicing
@@ -196,7 +197,7 @@ jobs:
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
#
@@ -243,14 +244,15 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-postgres:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 40
strategy:
fail-fast: false
@@ -353,7 +355,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -363,7 +366,7 @@ jobs:
- be-tests-mariadb
- be-tests-mysql
- be-tests-postgres
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
name: app-db-tests-result
if: always() && !cancelled()

View File

@@ -8,38 +8,31 @@ on:
required: true
type: string
permissions:
id-token: write
contents: read
jobs:
deploy:
name: Publish Athena JDBC Driver
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out the code
uses: actions/checkout@v4
- name: Set up Babashka
uses: turtlequeue/setup-babashka@2d4df498c7a578b4f3e906283f9af913590bdec7 # v1.7.0
uses: turtlequeue/setup-babashka@v1.7.0
with:
babashka-version: 1.12.197
- name: Set up AWS CLI
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.CI_MAVEN_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_S3_MAVEN_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_S3_MAVEN_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- name: Deploy Athena JDBC driver
run: ./bin/athena.bb "${VERSION}" --deploy
env:
VERSION: ${{ github.event.inputs.version }}
run: ./bin/athena.bb ${{ github.event.inputs.version }} --deploy
- name: Verify deployment
env:
VERSION: ${{ github.event.inputs.version }}
run: |
aws s3 ls s3://metabase-maven-downloads/com/metabase/athena-jdbc/"${VERSION}"/
echo "Athena JDBC driver version ${VERSION} has been deployed"
aws s3 ls s3://metabase-maven-downloads/com/metabase/athena-jdbc/${{ github.event.inputs.version }}/
echo "Athena JDBC driver version ${{ github.event.inputs.version }} has been deployed"

View File

@@ -7,10 +7,10 @@ on:
jobs:
update_pr:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
steps:
- uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2.1.0
- uses: tibdex/github-app-token@v2.1.0
id: generate-token
with:
app_id: ${{ secrets.METABASE_BOT_APP_ID }}

View File

@@ -20,7 +20,7 @@ jobs:
github.event.label.name == 'triple-backport'
)
)
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:

View File

@@ -17,7 +17,7 @@ on:
jobs:
setup-oss:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
outputs:
modules: ${{ steps.get-modules.outputs.modules }}
steps:
@@ -31,7 +31,7 @@ jobs:
needs: setup-oss
# don't run this workflow on a cron for forks
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 30
strategy:
fail-fast: false
@@ -57,14 +57,14 @@ jobs:
- name: Upload coverage to codecov.io
if: always()
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./target/coverage/codecov.json
flags: back-end
setup-ee:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
outputs:
modules: ${{ steps.get-modules.outputs.modules }}
steps:
@@ -78,7 +78,7 @@ jobs:
needs: setup-ee
# don't run this workflow on a cron for forks
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 30
strategy:
fail-fast: false
@@ -104,7 +104,7 @@ jobs:
- name: Upload coverage to codecov.io
if: always()
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./target/coverage/codecov.json

View File

@@ -14,7 +14,7 @@ concurrency:
jobs:
be-linter-clj-kondo:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
name: Clj-Kondo
steps:
@@ -26,7 +26,7 @@ jobs:
be-linter-eastwood:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 20
name: Eastwood
steps:
@@ -37,20 +37,20 @@ jobs:
name: Run Eastwood linter
be-linter-eastwood-test:
if: ${{ !inputs.skip && github.ref_name == 'master' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
timeout-minutes: 30
name: Eastwood (tests only)
name: Eastwood (test)
steps:
- uses: actions/checkout@v4
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- run: clojure -X:dev:ee:ee-dev:drivers:drivers-dev:test:eastwood/test
name: Run Eastwood linter on our backend tests
name: Run Eastwood linter on tests
be-tests:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 40
strategy:
fail-fast: false
@@ -138,13 +138,14 @@ jobs:
input-path: ./target/junit/
output-name: be-tests-java-${{ matrix.java-version }}-${{ matrix.job.edition }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.run-java-tests.outcome }}
- name: Publish Test Report (JUnit)
uses: dorny/test-reporter@3eeb9fc888e82e8be2fb356bbeec2750231672bc # v1
uses: dorny/test-reporter@v1
if: failure()
with:
path: "target/junit/**/*_test.xml"
@@ -166,7 +167,7 @@ jobs:
# as `:dev` dependencies). See #27009 for more context.
be-check:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
strategy:
matrix:
@@ -182,7 +183,7 @@ jobs:
be-cljfmt:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
name: Cljfmt
steps:
@@ -201,7 +202,7 @@ jobs:
- be-check
- be-tests
if: always() && !cancelled()
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
env:
needs: ${{ toJson(needs) }}

View File

@@ -10,10 +10,10 @@ on:
jobs:
backport-reminder:
name: Decide whether to backport or not
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: jesusvasquez333/verify-pr-label-action@657d111bbbe13e22bbd55870f1813c699bde1401 # v1.4.0
- uses: jesusvasquez333/verify-pr-label-action@v1.4.0
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
valid-labels: 'no-backport, backport, double-backport, triple-backport'

View File

@@ -5,7 +5,7 @@ on:
jobs:
check-source-branch:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
steps:
- name: Block master branch PRs
if: github.head_ref == 'master'

View File

@@ -14,7 +14,7 @@ on:
jobs:
start-message:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
@@ -45,7 +45,7 @@ jobs:
}).catch(console.error);
trigger-milestone-check:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
needs: start-message
steps:
@@ -66,7 +66,7 @@ jobs:
check-version:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
outputs:
ee: ${{ fromJson(steps.canonical_version.outputs.result).ee }}
@@ -118,7 +118,7 @@ jobs:
return versions;
check-commit:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- name: Check out the code to verify the release branch
@@ -150,7 +150,7 @@ jobs:
git checkout -
get-build-requirements:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
outputs:
java_version: ${{ fromJson(steps.dependencies.outputs.result).java_version }}
@@ -185,7 +185,7 @@ jobs:
build-uberjar-for-release:
needs: [check-version, check-commit, get-build-requirements]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 50
strategy:
matrix:

View File

@@ -10,7 +10,7 @@ on:
jobs:
test-build-scripts:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Prepare back-end environment

View File

@@ -39,8 +39,7 @@ concurrency:
jobs:
get-cache-keys:
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Get cache keys
@@ -53,7 +52,7 @@ jobs:
cypress-cache-key: ${{ steps.get-cache-keys.outputs.cypress-cache-key }}
generate-caches:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 30
needs: get-cache-keys
env:

View File

@@ -7,7 +7,7 @@ on:
jobs:
check-backport-script:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

View File

@@ -15,7 +15,7 @@ on:
jobs:
set-milestone:
name: Automatically set milestone
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 30
env:
isNewReleaseBranch: ${{ github.event_name == 'workflow_dispatch' }}

View File

@@ -14,14 +14,14 @@ concurrency:
jobs:
files-changed:
name: Check which files changed
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
frontend_all: ${{ steps.changes.outputs.frontend_all }}
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
@@ -30,7 +30,7 @@ jobs:
fe-chromatic:
needs: files-changed
if: contains(github.event.pull_request.labels.*.name, 'chromatic') || (github.ref_name == 'master' && needs.files-changed.outputs.frontend_all == 'true')
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v4
@@ -43,7 +43,7 @@ jobs:
- name: Compile CLJS
run: NODE_ENV=development bun run build-pure:cljs
- name: Publish to Chromatic
uses: chromaui/action@c03d144dc72e609acbb960489fdd1e1a4a23b34f # v10.2.0
uses: chromaui/action@v10.2.0
env:
PUBLISH_CHROMATIC: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
STORYBOOK_BUILD_TIMEOUT: 900000

View File

@@ -0,0 +1,360 @@
name: "Claude Code Bug Fix"
on:
issues:
types:
- labeled
pull_request_review:
types:
- submitted
workflow_dispatch:
inputs:
issue_number:
description: "Issue number to fix"
required: true
type: string
override_employee_check:
description: "Override employee check for issue creator"
required: false
default: false
type: boolean
jobs:
auto-fix-bug:
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
issues: write
pull-requests: write
id-token: write
if: |
(github.event_name == 'issues' && github.event.label.name == 'Claude Bug Fix' && github.event.issue.state == 'open') ||
(github.event_name == 'workflow_dispatch') ||
(github.event_name == 'pull_request_review' && github.event.review.state == 'changes_requested' && startsWith(github.event.pull_request.head.ref, 'claude-fix/'))
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get issue data and check employee status
id: get_issue
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { getIssueData } = require('${{ github.workspace }}/.github/scripts/get-issue-data.js');
try {
const result = await getIssueData({
context,
github,
manualIssueNumber: '${{ github.event.inputs.issue_number }}'
});
const { issueNumber, issueData, employeeComments, prReviews, triggerType, isIssueAuthorEmployee } = result;
// Check employee status and fail if not authorized
if (!result.isIssueAuthorEmployee && '${{ github.event.inputs.override_employee_check }}' !== 'true') {
core.setFailed(`User ${result.issueData.user.login} is not a Metabase employee. Skipping bug fix automation.`);
}
core.setOutput('issue_number', issueNumber);
core.setOutput('issue_data', JSON.stringify(issueData));
core.setOutput('issue_comments', JSON.stringify(employeeComments));
core.setOutput('pr_reviews', JSON.stringify(prReviews));
core.setOutput('trigger_type', triggerType);
} catch (error) {
core.setFailed(error.message);
}
- name: Find linked Linear issue
id: find_linear
continue-on-error: true
uses: actions/github-script@v7
env:
LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
ISSUE_NUMBER: ${{ steps.get_issue.outputs.issue_number }}
with:
script: |
const { findLinearIssue } = require('${{ github.workspace }}/.github/scripts/find-linear-issue.js');
const githubIssueUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/issues/${process.env.ISSUE_NUMBER}`;
const result = await findLinearIssue({
githubIssueUrl,
linearApiKey: process.env.LINEAR_API_KEY
});
if (result.success) {
console.log(`Found Linear issue: ${result.issue}`);
core.setOutput('linear_issue', result.issue);
} else {
console.log(`Could not find Linear issue: ${result.message}`);
}
- name: Set up git configuration
run: |
git config --global user.name "Claude Code[bot]"
git config --global user.email "noreply@anthropic.com"
- name: Prepare issue context and bug fix prompt
id: prepare_prompt
uses: actions/github-script@v7
env:
ISSUE_DATA: ${{ steps.get_issue.outputs.issue_data }}
ISSUE_COMMENTS: ${{ steps.get_issue.outputs.issue_comments }}
PR_REVIEWS: ${{ steps.get_issue.outputs.pr_reviews }}
TRIGGER_TYPE: ${{ steps.get_issue.outputs.trigger_type }}
with:
script: |
const issueData = JSON.parse(process.env.ISSUE_DATA);
const issueComments = JSON.parse(process.env.ISSUE_COMMENTS);
const prReviews = JSON.parse(process.env.PR_REVIEWS);
const triggerType = process.env.TRIGGER_TYPE;
const issueNumber = '${{ steps.get_issue.outputs.issue_number }}';
// Convert issue title to kebab case and create branch name
const issueTitle = issueData.title || 'untitled';
const kebabTitle = issueTitle
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
.replace(/-+/g, '-')
.substring(0, 50);
const branchName = `claude-fix/issue-${issueNumber}-${kebabTitle}`;
// Format data for bash environment
const formattedComments = issueComments.length > 0
? issueComments.map(comment =>
`**Comment by @${comment.user.login} on ${comment.created_at}:**\n${comment.body}`
).join('\n\n---\n\n')
: '';
const formattedReviews = prReviews.length > 0
? prReviews.map(review =>
`**Review by @${review.user.login} on ${review.submitted_at} (Changes Requested):**\n${review.body || 'No review comment provided'}`
).join('\n\n---\n\n')
: '';
core.exportVariable('BRANCH_NAME', branchName);
core.exportVariable('ISSUE_NUMBER', issueNumber);
core.exportVariable('ISSUE_TITLE', issueData.title);
core.exportVariable('ISSUE_AUTHOR', issueData.user.login);
core.exportVariable('ISSUE_CREATED', issueData.created_at);
core.exportVariable('ISSUE_BODY', issueData.body || 'No description provided');
core.exportVariable('ISSUE_COMMENTS_FORMATTED', formattedComments);
core.exportVariable('PR_REVIEWS_FORMATTED', formattedReviews);
core.exportVariable('TRIGGER_TYPE', triggerType);
- name: Generate bug fix prompt
run: |
cat << 'EOF' >> $GITHUB_ENV
BUG_FIX_PROMPT<<PROMPT_END
You are helping to fix a bug reported in GitHub issue #${{ env.ISSUE_NUMBER }}.
## Bug Report Details
**Title:** ${{ env.ISSUE_TITLE }}
**Reporter:** ${{ env.ISSUE_AUTHOR }}
**Created:** ${{ env.ISSUE_CREATED }}
**Description:**
${{ env.ISSUE_BODY }}
**Comments:**
${{ env.ISSUE_COMMENTS_FORMATTED }}
EOF
# Add review feedback section only if this is a review trigger
if [ "${{ env.TRIGGER_TYPE }}" = "pull_request_review" ]; then
cat << 'EOF' >> $GITHUB_ENV
## Previous Fix Attempt - Review Feedback (MUST ADDRESS)
Your previous automated fix attempt received the following feedback that needs to be addressed:
${{ env.PR_REVIEWS_FORMATTED }}
EOF
fi
# Add the rest of the prompt (always the same)
cat << 'EOF' >> $GITHUB_ENV
## Instructions
1. **Analyze the issue description and comments** - Understand what the issue is describing
a. Pay particular attention to reproduction steps and if there's an agreed upon fix.
2. **Search the codebase** - Use Grep and Glob tools to find relevant files
3. **Implement a fix** - Use the appropriate write skill based on the file types:
- Use clojure-write for Clojure/ClojureScript files
- Use typescript-write for TypeScript/JavaScript files
- Follow the coding standards and patterns in each skill
4. **Test the fix** - Run appropriate tests as specified in the skills
5. **Verify the fix** - Ensure tests pass and code follows conventions
## Important Guidelines
- Use the appropriate write skill for the language you're working in
- Write failing tests first, then fix them
- Work in small, testable increments
- Don't commit changes - leave that for the workflow
- IMPORTANT: Focus only on fixing the reported bug, don't make unrelated changes
## Scratchpad Directory
A `.claude-scratchpad/` directory has been created for your temporary files:
- Use this directory for ALL temporary verification files. However, prefer using production test files rather than adhoc ones.
- Only modify actual production code in the main repository directories
- The scratchpad will be cleaned up automatically - nothing from it will be committed
Start by understanding the bug and then systematically work toward a solution.
PROMPT_END
EOF
- name: Determine branch strategy
run: |
BRANCH_NAME="${{ env.BRANCH_NAME }}"
if git branch -r --list "origin/${BRANCH_NAME}" | grep -q .; then
echo "Branch already exists: $BRANCH_NAME"
echo "Will push to existing branch and skip PR creation"
echo "BRANCH_EXISTS=true" >> $GITHUB_ENV
else
echo "Creating new branch: $BRANCH_NAME"
echo "Will create new PR"
echo "BRANCH_EXISTS=false" >> $GITHUB_ENV
fi
# Export the branch name
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
- name: Create scratchpad directory for Claude
run: |
# Create a scratchpad directory for Claude to use for temporary files
mkdir -p .claude-scratchpad
echo "Scratchpad directory created for Claude's temporary verification files"
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Generate GitHub App Token for Claude
uses: actions/create-github-app-token@v1
id: claude-app-token
with:
app-id: ${{ secrets.METABASE_BOT_APP_ID }}
private-key: ${{ secrets.METABASE_BOT_APP_PRIVATE_KEY }}
- name: Generate Bug Fix with Claude Code
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ steps.claude-app-token.outputs.token }}
prompt: ${{ env.BUG_FIX_PROMPT }}
claude_args: |
--allowedTools "Bash(bun run test-unit*),Bash(bun run lint-eslint-pure),Bash(./bin/mage*),Bash(clojure*),Bash(find*),Bash(ls*),Bash(grep*),Write,Read,Glob,Grep,Edit,MultiEdit"
--disallowedTools "Bash(git commit*),Bash(git push*),Bash(gh*)"
- name: Clean up scratchpad directory
run: |
# Remove the scratchpad directory so its contents don't get committed
rm -rf .claude-scratchpad/
# Remove output file generated by Claude Code action
rm -f output.txt
echo "Scratchpad directory and action output files cleaned up"
- name: Check for changes and analysis
id: check_changes
run: |
# Now check for actual code changes (excluding analysis file)
if [ -n "$(git status --porcelain)" ]; then
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "Changes detected:"
git status --short
else
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "No changes made by Claude."
fi
- name: Get issue team labels and prepare reviewers
if: steps.check_changes.outputs.has_changes == 'true'
id: prepare_reviewers
uses: actions/github-script@v7
env:
ISSUE_DATA: ${{ steps.get_issue.outputs.issue_data }}
with:
script: |
const issueData = JSON.parse(process.env.ISSUE_DATA);
const issueLabels = issueData.labels.map(label => label.name);
const teamLabels = issueLabels.filter(label => label.startsWith('.Team/'));
const issueCreator = issueData.user.login;
core.setOutput('team_labels', teamLabels.join(','));
core.setOutput('reviewers', issueCreator);
- name: Create Pull Request
id: create_pr
if: steps.check_changes.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ env.BRANCH_NAME }}
base: master
commit-message: |
Fix: ${{ env.ISSUE_TITLE }}
Fixes #${{ env.ISSUE_NUMBER }}
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
committer: "Claude Code[bot] <noreply@anthropic.com>"
author: "Claude Code[bot] <noreply@anthropic.com>"
title: "Fix: ${{ env.ISSUE_TITLE }}"
body: |
This PR automatically fixes the bug reported in #${{ env.ISSUE_NUMBER }}.
${{ steps.find_linear.outputs.linear_issue && format('Closes {0}', steps.find_linear.outputs.linear_issue) || '' }}
## Bug Report
**Original Issue:** #${{ env.ISSUE_NUMBER }}
**Reporter:** @${{ env.ISSUE_AUTHOR }}
**Issue Title:** ${{ env.ISSUE_TITLE }}
## Automated Fix
🤖 This fix was generated automatically by Claude Code based on the issue description.
**Please review carefully:**
- [ ] The fix addresses the reported issue
- [ ] Tests pass and code follows conventions
- [ ] No unrelated changes were introduced
- [ ] The solution is appropriate and maintainable
## Next Steps
- Review the changes and test thoroughly
- If the fix looks good, approve and merge
- If issues are found, either fix them or close this PR
---
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
labels: |
${{ steps.prepare_reviewers.outputs.team_labels }}
automated-fix
ci skip
reviewers: ${{ steps.prepare_reviewers.outputs.reviewers }}
assignees: ${{ github.actor }}
- name: Log existing branch update
if: steps.check_changes.outputs.has_changes == 'true' && env.BRANCH_EXISTS == 'true'
uses: actions/github-script@v7
with:
script: |
console.log('🔄 Updated existing branch: ${{ env.BRANCH_NAME }}');
console.log('The changes have been pushed to the existing PR for this issue.');
- name: Log analysis for no changes
if: steps.check_changes.outputs.has_changes == 'false'
uses: actions/github-script@v7
with:
script: |
console.log('🤖 No code changes were made by Claude.');

View File

@@ -14,14 +14,14 @@ concurrency:
jobs:
files-changed:
name: Check which files changed
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
cljs: ${{ steps.changes.outputs.cljs }}
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
@@ -30,7 +30,7 @@ jobs:
shared-tests-cljs:
needs: files-changed
if: needs.files-changed.outputs.cljs == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v4

View File

@@ -10,14 +10,14 @@ on:
jobs:
files-changed:
name: Check which files changed
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
codeql: ${{ steps.changes.outputs.codeql }}
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
@@ -25,7 +25,7 @@ jobs:
analyze:
needs: files-changed
if: needs.files-changed.outputs.codeql == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v4

View File

@@ -8,8 +8,7 @@ on:
jobs:
codespell:
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
@@ -68,7 +67,7 @@ jobs:
- name: Fix spelling errors with Claude Code
if: steps.codespell_check.outcome == 'failure'
uses: anthropics/claude-code-action@3ac52d0da9f8ec9ca7b4dc23bb477e36ef9c77a9 # v1
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ steps.claude-app-token.outputs.token }}
@@ -83,7 +82,7 @@ jobs:
- name: Create Pull Request
if: steps.codespell_check.outcome == 'failure'
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: claude-fix/codespell-${{ steps.date.outputs.date }}

View File

@@ -48,7 +48,7 @@ on:
jobs:
containerize:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 15
outputs:
platforms: ${{ steps.platforms.outputs.result }}
@@ -84,19 +84,19 @@ jobs:
- name: Move the Uberjar to the context dir
run: mv ./metabase.jar bin/docker/.
- name: Login to Docker Hub
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
uses: docker/login-action@v3
with:
username: ${{ inputs.release == 'true' && secrets.DOCKERHUB_RELEASE_USERNAME || secrets.DOCKERHUB_USERNAME }}
password: ${{ inputs.release == 'true' && secrets.DOCKERHUB_RELEASE_TOKEN || secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU
if: contains(steps.platforms.outputs.result, 'arm')
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
if: contains(steps.platforms.outputs.result, 'arm')
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
uses: docker/setup-buildx-action@v3
- name: Build multi-arch container
if: contains(steps.platforms.outputs.result, 'arm')
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
uses: docker/build-push-action@v6
with:
context: bin/docker/.
platforms: ${{ steps.platforms.outputs.result }}
@@ -117,12 +117,12 @@ jobs:
bin/docker/.
verify-docker-pull:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
needs: containerize
timeout-minutes: 15
steps:
- name: Login to Docker Hub
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
uses: docker/login-action@v3
with:
username: ${{ inputs.release == 'true' && secrets.DOCKERHUB_RELEASE_USERNAME || secrets.DOCKERHUB_USERNAME }}
password: ${{ inputs.release == 'true' && secrets.DOCKERHUB_RELEASE_TOKEN || secrets.DOCKERHUB_TOKEN }}
@@ -142,7 +142,7 @@ jobs:
timeout-minutes: 15
steps:
- name: Login to Docker Hub
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
uses: docker/login-action@v3
with:
username: ${{ inputs.release == 'true' && secrets.DOCKERHUB_RELEASE_USERNAME || secrets.DOCKERHUB_USERNAME }}
password: ${{ inputs.release == 'true' && secrets.DOCKERHUB_RELEASE_TOKEN || secrets.DOCKERHUB_TOKEN }}

View File

@@ -6,7 +6,7 @@ on:
jobs:
get-container-info:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
name: Get container info
outputs:
@@ -68,7 +68,7 @@ jobs:
strategy:
matrix:
edition: ${{ fromJson(needs.get-container-info.outputs.editions) }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
name: Run Trivy vulnerability scanner
steps:
- name: Check out the code
@@ -76,7 +76,7 @@ jobs:
with:
ref: ${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1
uses: aquasecurity/trivy-action@0.29.0
env:
TRIVY_OFFLINE_SCAN: true
repo: ${{ fromJson(needs.get-container-info.outputs[matrix.edition]).repo }}
@@ -85,6 +85,7 @@ jobs:
image-ref: docker.io/${{ env.repo }}:${{ env.tag }}
format: sarif
output: trivy-results.sarif
version: "v0.57.1"
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
with:
@@ -93,7 +94,7 @@ jobs:
post-comment:
needs: [get-container-info, containerize]
if: github.event_name == 'pull_request'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
name: Post PR comment
steps:
- name: Check out the code
@@ -106,7 +107,7 @@ jobs:
edition: ee
- name: Post PR comment
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2
uses: marocchino/sticky-pull-request-comment@v2
with:
header: docker-build-status
message: |

View File

@@ -8,21 +8,21 @@ on:
jobs:
files-changed:
name: Check which files changed
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
frontend_embedding_sources: ${{ steps.changes.outputs.frontend_embedding_sources }}
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
filters: .github/file-paths.yaml
pr-title-reminder:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
permissions:
pull-requests: write

View File

@@ -7,8 +7,7 @@ on:
jobs:
fe-test-coverage:
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
@@ -23,7 +22,7 @@ jobs:
--coverage \
--testTimeout=60000
- name: Upload coverage to codecov.io
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5
uses: codecov/codecov-action@v5
with:
files: ./coverage/lcov.info
flags: front-end

View File

@@ -25,7 +25,7 @@ concurrency:
jobs:
migrations-h2-ee:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
env:
CI: 'true'
@@ -39,23 +39,23 @@ jobs:
head-ref: ${{ env.HEAD_REF }}
migrations-postgres-14-ee:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
env:
CI: 'true'
MB_DB_TYPE: postgres
MB_DB_PORT: 5432
MB_DB_HOST: localhost
MB_DB_DBNAME: mb_test
MB_DB_USER: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: circle_test
services:
postgres:
image: postgres:14-alpine
ports:
- "5432:5432"
env:
POSTGRES_USER: mb_test
POSTGRES_DB: mb_test
POSTGRES_USER: circle_test
POSTGRES_DB: circle_test
POSTGRES_HOST_AUTH_METHOD: trust
steps:
- uses: actions/checkout@v4
@@ -65,23 +65,23 @@ jobs:
head-ref: ${{ env.HEAD_REF }}
migrations-postgres-latest-ee:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
env:
CI: 'true'
MB_DB_TYPE: postgres
MB_DB_PORT: 5432
MB_DB_HOST: localhost
MB_DB_DBNAME: mb_test
MB_DB_USER: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: circle_test
services:
postgres:
image: postgres:latest
image: circleci/postgres:latest
ports:
- "5432:5432"
env:
POSTGRES_USER: mb_test
POSTGRES_DB: mb_test
POSTGRES_USER: circle_test
POSTGRES_DB: circle_test
POSTGRES_HOST_AUTH_METHOD: trust
steps:
- uses: actions/checkout@v4
@@ -91,23 +91,20 @@ jobs:
head-ref: ${{ env.HEAD_REF }}
migrations-mysql-8-4-ee:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
env:
CI: 'true'
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: root
services:
mysql:
image: mysql:8.4
image: cimg/mysql:8.4
ports:
- "3306:3306"
env:
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: mb_test
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/cross-branch-migration-test
@@ -116,14 +113,14 @@ jobs:
head-ref: ${{ env.HEAD_REF }}
migrations-mysql-latest-ee:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
env:
CI: 'true'
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
services:
@@ -131,7 +128,7 @@ jobs:
image: mysql:latest
env:
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: mb_test
MYSQL_DATABASE: circle_test
ports:
- "3306:3306"
steps:
@@ -142,23 +139,20 @@ jobs:
head-ref: ${{ env.HEAD_REF }}
migrations-mariadb-10-6-ee:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
env:
CI: 'true'
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: root
services:
mariadb:
image: metabase/mariadb:10.6 # https://github.com/metabase/metabase-mariadb-docker-image
image: circleci/mariadb:10.6
ports:
- "3306:3306"
env:
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: true
MARIADB_DATABASE: mb_test
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/cross-branch-migration-test
@@ -167,23 +161,20 @@ jobs:
head-ref: ${{ env.HEAD_REF }}
migrations-mariadb-latest-ee:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
env:
CI: 'true'
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: root
services:
mariadb:
image: mariadb:latest
image: circleci/mariadb:latest
ports:
- "3306:3306"
env:
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: true
MARIADB_DATABASE: mb_test
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/cross-branch-migration-test

View File

@@ -25,8 +25,8 @@ on:
jobs:
# Generate matrix for scheduled/PR runs
generate-matrix:
if: github.event_name != 'workflow_dispatch' && github.repository == 'metabase/metabase'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
if: github.event_name != 'workflow_dispatch'
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
@@ -47,9 +47,9 @@ jobs:
# Matrix-based tests for scheduled/PR runs
test-matrix:
if: github.event_name != 'workflow_dispatch' && github.repository == 'metabase/metabase'
if: github.event_name != 'workflow_dispatch'
needs: generate-matrix
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
@@ -61,38 +61,13 @@ jobs:
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare Cypress environment
uses: ./.github/actions/prepare-cypress
- name: Run cross-version test
env:
CURRENT_VERSION: ${{ vars.CURRENT_VERSION }}
RESULT_FILE: ${{ runner.temp }}/cross-version-result-${{ matrix.source }}-${{ matrix.target }}.json
run: |
cd cross-version
./test.sh --source "${{ matrix.source }}" --target "${{ matrix.target }}"
- name: Upload failure result
uses: actions/upload-artifact@v4
if: failure()
with:
name: failure-result-${{ matrix.source }}-${{ matrix.target }}
path: ${{ runner.temp }}/cross-version-result-${{ matrix.source }}-${{ matrix.target }}.json
if-no-files-found: ignore
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-recording-${{ matrix.source }}-${{ matrix.target }}
path: |
./cypress
./logs/test.log
if-no-files-found: ignore
- name: Show logs on failure
if: failure()
run: |
@@ -100,92 +75,10 @@ jobs:
docker compose logs metabase || true
docker compose logs postgres || true
# Notify Slack on nightly failures
notify-on-failure:
if: >-
always()
&& github.event_name == 'schedule'
&& github.repository == 'metabase/metabase'
&& needs.test-matrix.result == 'failure'
needs: [test-matrix]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Download failure results
uses: actions/download-artifact@v4
continue-on-error: true
with:
pattern: failure-result-*
path: failure-results
merge-multiple: true
- name: Notify Slack
continue-on-error: true
uses: actions/github-script@v7
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
with:
script: |
const fs = require('fs');
const path = require('path');
const { buildFailureResults, sendCrossVersionSlackNotification } = require('${{ github.workspace }}/release/dist/index.cjs');
// Get all failed jobs from the GitHub API
const { owner, repo } = context.repo;
const jobInfo = await github.rest.actions.listJobsForWorkflowRun({
owner,
repo,
run_id: context.runId,
per_page: 100,
});
const failedJobs = jobInfo.data.jobs
.filter(job => job.status === 'completed' && job.conclusion === 'failure' && job.name.startsWith('test-matrix'))
.map(job => ({ name: job.name, url: job.html_url }));
if (failedJobs.length === 0) {
console.log('No failed test-matrix jobs found');
return;
}
// Load artifact data for enrichment (phase)
const resultsDir = 'failure-results';
const artifactData = new Map();
if (fs.existsSync(resultsDir)) {
for (const file of fs.readdirSync(resultsDir)) {
if (!file.endsWith('.json')) continue;
try {
const result = JSON.parse(fs.readFileSync(path.join(resultsDir, file), 'utf8'));
artifactData.set(`${result.source}-${result.target}`, result);
} catch (e) {
console.log(`Skipping malformed result: ${file}`);
}
}
}
const failures = buildFailureResults(failedJobs, artifactData);
const runUrl = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${context.runId}`;
const slackBotToken = process.env.SLACK_BOT_TOKEN;
if (!slackBotToken) {
console.log('SLACK_BOT_TOKEN is not set; skipping Slack notification.');
return;
}
await sendCrossVersionSlackNotification(failures, runUrl, slackBotToken);
console.log('Slack notification sent');
# Manual test for workflow_dispatch
test-manual:
if: github.event_name == 'workflow_dispatch'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
@@ -194,12 +87,6 @@ jobs:
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare Cypress environment
uses: ./.github/actions/prepare-cypress
- name: Run cross-version test
env:
CURRENT_VERSION: ${{ vars.CURRENT_VERSION }}
@@ -207,16 +94,6 @@ jobs:
cd cross-version
./test.sh --source "${{ inputs.source_version }}" --target "${{ inputs.target_version }}"
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-recording-${{ inputs.source_version }}-${{ inputs.target_version }}
path: |
./cypress
./logs/test.log
if-no-files-found: ignore
- name: Show logs on failure
if: failure()
run: |

View File

@@ -7,8 +7,7 @@ on:
jobs:
notify-disabled-drivers:
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/setup-node@v4

View File

@@ -21,7 +21,7 @@ permissions:
jobs:
update-docs:
name: Update documentation for ${{ inputs.target_branch }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 30
steps:
- name: Checkout code

View File

@@ -7,7 +7,7 @@ on:
jobs:
link-checker:
name: Check documentation links
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
@@ -27,7 +27,7 @@ jobs:
- name: Run link checker
id: link-check
uses: lycheeverse/lychee-action@f613c4a64e50d792e0b31ec34bbcbba12263c6a6 # v2.3.0
uses: lycheeverse/lychee-action@v2.3.0
with:
fail: true
args: docs --config ./.lychee/config.toml --offline

View File

@@ -2,12 +2,11 @@ name: Auto-update documentation (master)
on:
schedule:
- cron: "0 21 * * 1-5" # Every Monday through Friday at 9 PM UTC
- cron: "0 1 * * 1-5" # Every Monday through Friday at 1 AM UTC
workflow_dispatch:
jobs:
update-master-docs:
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
name: Call documentation update for master
uses: ./.github/workflows/docs-generate-base.yml
with:

View File

@@ -2,7 +2,7 @@ name: Auto-update documentation (release)
on:
schedule:
- cron: "0 22 * * 1-5" # Every Monday through Friday at 10 PM UTC
- cron: "0 2 * * 1-5" # Every Monday through Friday at 2 AM UTC
workflow_dispatch:
inputs:
target_branch:
@@ -13,7 +13,6 @@ on:
jobs:
update-release-docs:
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
name: Call documentation update for release branch
uses: ./.github/workflows/docs-generate-base.yml
with:

View File

@@ -49,7 +49,7 @@ jobs:
be-tests-athena-ee:
if: inputs.driver == 'Athena'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -68,7 +68,7 @@ jobs:
be-tests-bigquery-cloud-sdk-ee:
if: inputs.driver == 'BigQuery'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -89,7 +89,7 @@ jobs:
be-tests-druid-ee:
if: inputs.driver == 'Druid'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -111,7 +111,7 @@ jobs:
be-tests-mariadb-10-6-ee:
if: inputs.driver == 'Maria DB'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -119,17 +119,14 @@ jobs:
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
services:
mariadb:
image: metabase/mariadb:10.6 # https://github.com/metabase/metabase-mariadb-docker-image
image: circleci/mariadb:10.6
ports:
- "3306:3306"
env:
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: true
MARIADB_DATABASE: mb_test
steps:
- uses: actions/checkout@v4
- name: Test MariaDB driver (10.6)
@@ -140,7 +137,7 @@ jobs:
be-tests-mariadb-latest-ee:
if: inputs.driver == 'Maria DB (latest)'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -148,17 +145,14 @@ jobs:
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
services:
mariadb:
image: mariadb:latest
image: circleci/mariadb:latest
ports:
- "3306:3306"
env:
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: true
MARIADB_DATABASE: mb_test
steps:
- uses: actions/checkout@v4
- name: Test MariaDB driver (latest)
@@ -169,7 +163,7 @@ jobs:
be-tests-mongo-4-4-ee:
if: inputs.driver == 'Mongo 4'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -191,7 +185,7 @@ jobs:
be-tests-mongo-4-4-ssl-ee:
if: inputs.driver == 'Mongo 4 (SSL)'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -225,7 +219,7 @@ jobs:
be-tests-mongo-5-0-ee:
if: inputs.driver == 'Mongo 5'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -247,7 +241,7 @@ jobs:
be-tests-mongo-5-0-ssl-ee:
if: inputs.driver == 'Mongo 5 (SSL)'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -281,7 +275,7 @@ jobs:
be-tests-mongo-latest-ee:
if: inputs.driver == 'Mongo (latest)'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -290,7 +284,7 @@ jobs:
MB_MONGO_TEST_PASSWORD: metasample123
services:
mongodb:
image: mongo:latest
image: circleci/mongo:latest
ports:
- "27017:27017"
env:
@@ -306,7 +300,7 @@ jobs:
be-tests-mysql-8-4-ee:
if: inputs.driver == 'MySQL'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -314,17 +308,14 @@ jobs:
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
services:
mysql:
image: mysql:8.4
image: cimg/mysql:8.4
ports:
- "3306:3306"
env:
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: mb_test
steps:
- uses: actions/checkout@v4
- name: Test MySQL driver (8.4)
@@ -335,7 +326,7 @@ jobs:
be-tests-mysql-latest-ee:
if: inputs.driver == 'MySQL (latest)'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -343,7 +334,7 @@ jobs:
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
# set up env vars for something named "MYSQL_SSL" to run MySQL SSL tests verifying connectivity with PEM cert
@@ -373,7 +364,7 @@ jobs:
be-tests-oracle-18-4-ee:
if: inputs.driver == 'Oracle 18'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -399,7 +390,7 @@ jobs:
be-tests-oracle-21-3-ee:
if: inputs.driver == 'Oracle 21'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -434,7 +425,7 @@ jobs:
be-tests-postgres-ee:
if: inputs.driver == 'Postgres'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -464,7 +455,7 @@ jobs:
be-tests-postgres-latest-ee:
if: inputs.driver == 'Postgres (latest)'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -472,20 +463,20 @@ jobs:
MB_DB_TYPE: postgres
MB_DB_PORT: 5432
MB_DB_HOST: localhost
MB_DB_DBNAME: mb_test
MB_DB_USER: mb_test
MB_POSTGRESQL_TEST_USER: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: circle_test
MB_POSTGRESQL_TEST_USER: circle_test
MB_POSTGRES_SSL_TEST_SSL: true
MB_POSTGRES_SSL_TEST_SSL_MODE: verify-full
MB_POSTGRES_SSL_TEST_SSL_ROOT_CERT_PATH: 'test-resources/certificates/us-east-2-bundle.pem'
services:
postgres:
image: postgres:latest
image: circleci/postgres:latest
ports:
- "5432:5432"
env:
POSTGRES_USER: mb_test
POSTGRES_DB: mb_test
POSTGRES_USER: circle_test
POSTGRES_DB: circle_test
POSTGRES_HOST_AUTH_METHOD: trust
steps:
- uses: actions/checkout@v4
@@ -497,7 +488,7 @@ jobs:
be-tests-presto-jdbc-ee:
if: inputs.driver == 'Presto JDBC'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -546,7 +537,7 @@ jobs:
be-tests-redshift-ee:
if: inputs.driver == 'Redshift'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -565,7 +556,7 @@ jobs:
be-tests-snowflake-ee:
if: inputs.driver == 'Snowflake'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -586,7 +577,7 @@ jobs:
be-tests-sparksql-ee:
if: inputs.driver == 'SparkSQL'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -606,7 +597,7 @@ jobs:
be-tests-sqlite-ee:
if: inputs.driver == 'SQLite'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -621,7 +612,7 @@ jobs:
be-tests-sqlserver-2017-ee:
if: inputs.driver == 'SQL Server 2017'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -648,7 +639,7 @@ jobs:
be-tests-sqlserver-2022-ee:
if: inputs.driver == 'SQL Server 2022'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -675,7 +666,7 @@ jobs:
be-tests-starburst-ee:
if: inputs.driver == 'Starburst'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
env:
CI: 'true'
@@ -700,14 +691,14 @@ jobs:
login-to-ecr:
if: inputs.driver == 'Vertica'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 15
permissions:
id-token: write
contents: read
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.CI_IAM_ROLE }}
role-session-name: GitHub_to_AWS_via_FederatedOIDC
@@ -729,7 +720,7 @@ jobs:
be-tests-vertica-ee:
if: inputs.driver == 'Vertica'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
needs: login-to-ecr
timeout-minutes: 90
env:

View File

@@ -15,7 +15,7 @@ jobs:
# This job determines which driver tests should run based on PR context.
# All decision logic is consolidated in mage driver-decisions.
determine-driver-skips:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
outputs:
# All driver run decisions (from mage driver-decisions)
h2-should-run: ${{ steps.driver-decisions.outputs.h2-should-run }}
@@ -72,8 +72,8 @@ jobs:
# All decision logic is in mage - it analyzes module dependencies,
# branch context, labels, and file changes to decide what runs.
MAGE_ARGS=(
--git-ref="${BASE_REF}"
--is-master-or-release="${IS_MASTER_OR_RELEASE}"
--git-ref="${{ github.event.pull_request.base.ref || github.ref_name }}"
--is-master-or-release="${{ github.ref_name == 'master' || startsWith(github.ref_name, 'release-') }}"
--pr-labels="${{ join(github.event.pull_request.labels.*.name, ',') }}"
--skip="${{ inputs.skip }}"
)
@@ -82,20 +82,14 @@ jobs:
echo ""
# First call: show human-readable output for debugging
./bin/mage -driver-decisions "${MAGE_ARGS[@]}"
echo ""
echo "Want to force-run a specific driver? Add a ci:run-<driver> or ci:run-all-drivers label to your PR."
echo "Run './bin/mage -driver-decisions -h' locally for the full list of drivers and labels."
# Second call: output only key=value lines for GITHUB_OUTPUT
./bin/mage -driver-decisions "${MAGE_ARGS[@]}" --github-output-only >> $GITHUB_OUTPUT
env:
BASE_REF: ${{ github.event.pull_request.base.ref || github.ref_name }}
IS_MASTER_OR_RELEASE: ${{ github.ref_name == 'master' || startsWith(github.ref_name, 'release-') }}
shell: bash
be-tests-athena-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.athena-should-run == 'true' || needs.determine-driver-skips.outputs.athena-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: 'true'
@@ -137,7 +131,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -145,7 +140,7 @@ jobs:
be-tests-bigquery-cloud-sdk-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.bigquery-should-run == 'true' || needs.determine-driver-skips.outputs.bigquery-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
@@ -202,7 +197,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -216,7 +212,7 @@ jobs:
be-tests-clickhouse-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.clickhouse-should-run == 'true' || needs.determine-driver-skips.outputs.clickhouse-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
strategy:
fail-fast: false
@@ -259,7 +255,7 @@ jobs:
run: |
sudo echo "127.0.0.1 server.clickhouseconnect.test" | sudo tee -a /etc/hosts
- name: Start ClickHouse in Docker
uses: hoverkraft-tech/compose-action@802a148945af6399a338c7906c267331b39a71af # v2.0.0
uses: hoverkraft-tech/compose-action@v2.0.0
with:
compose-file: "modules/drivers/clickhouse/docker-compose.yml"
down-flags: "--volumes"
@@ -284,7 +280,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -298,7 +295,7 @@ jobs:
be-tests-druid-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.druid-should-run == 'true' || needs.determine-driver-skips.outputs.druid-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: 'true'
@@ -338,7 +335,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -346,7 +344,7 @@ jobs:
be-tests-druid-jdbc-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.druid-jdbc-should-run == 'true' || needs.determine-driver-skips.outputs.druid-jdbc-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: 'true'
@@ -386,7 +384,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -394,7 +393,7 @@ jobs:
be-tests-databricks-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.databricks-should-run == 'true' || needs.determine-driver-skips.outputs.databricks-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: 'true'
@@ -434,7 +433,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -442,7 +442,7 @@ jobs:
be-tests-databricks-multi-catalog-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.databricks-should-run == 'true' || needs.determine-driver-skips.outputs.databricks-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: 'true'
@@ -483,7 +483,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -491,7 +492,7 @@ jobs:
be-tests-h2:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.h2-should-run == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: 'true'
@@ -513,7 +514,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -521,7 +523,7 @@ jobs:
be-tests-h2-oss:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.h2-should-run == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: 'true'
@@ -544,7 +546,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -552,7 +555,7 @@ jobs:
be-tests-mysql-mariadb:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.mysql-mariadb-should-run == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
strategy:
fail-fast: false
@@ -560,13 +563,13 @@ jobs:
version:
- name: MariaDB 10.6
junit-name: be-tests-mariadb-10-6-ee
image: metabase/mariadb:10.6 # https://github.com/metabase/metabase-mariadb-docker-image
image: circleci/mariadb:10.6
env:
enable-ssl-tests: 'false'
enable-aws-iam-tests: 'false'
- name: MariaDB Latest
junit-name: be-tests-mariadb-latest-ee
image: mariadb:latest
image: circleci/mariadb:latest
env:
enable-ssl-tests: 'false'
enable-aws-iam-tests: 'false'
@@ -599,7 +602,7 @@ jobs:
- "3306:3306"
env:
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: mb_test
MYSQL_DATABASE: circle_test
env:
# Only run old migrations tests on pushes to master or release branches. All other branches should skip tests
# with the tag `mb/old-migrations-test`. `__ADDITIONAL_EXCLUDED_TAG__` is not used anywhere outside of splicing
@@ -622,7 +625,7 @@ jobs:
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
#
@@ -674,7 +677,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -688,7 +692,7 @@ jobs:
be-tests-mongo:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.mongo-should-run == 'true' || needs.determine-driver-skips.outputs.mongo-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
strategy:
fail-fast: false
@@ -754,7 +758,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -768,7 +773,7 @@ jobs:
be-tests-mongo-ssl:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.mongo-ssl-should-run == 'true' || needs.determine-driver-skips.outputs.mongo-ssl-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
strategy:
fail-fast: false
@@ -836,7 +841,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -844,7 +850,7 @@ jobs:
be-tests-mongo-sharded-cluster-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.mongo-sharded-cluster-should-run == 'true' || needs.determine-driver-skips.outputs.mongo-sharded-cluster-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: 'true'
@@ -881,7 +887,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -889,7 +896,7 @@ jobs:
be-tests-oracle:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.oracle-should-run == 'true' || needs.determine-driver-skips.outputs.oracle-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
strategy:
fail-fast: false
@@ -966,7 +973,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -974,7 +982,7 @@ jobs:
be-tests-postgres:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.postgres-should-run == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
strategy:
fail-fast: false
@@ -1070,7 +1078,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -1084,7 +1093,7 @@ jobs:
be-tests-presto-jdbc-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.presto-jdbc-should-run == 'true' || needs.determine-driver-skips.outputs.presto-jdbc-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: 'true'
@@ -1157,7 +1166,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -1165,7 +1175,7 @@ jobs:
be-tests-redshift-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.redshift-should-run == 'true' || needs.determine-driver-skips.outputs.redshift-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
strategy:
fail-fast: false
@@ -1241,7 +1251,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -1255,7 +1266,7 @@ jobs:
be-tests-snowflake-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.snowflake-should-run == 'true' || needs.determine-driver-skips.outputs.snowflake-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
@@ -1321,7 +1332,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -1335,7 +1347,7 @@ jobs:
be-tests-sparksql-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.sparksql-should-run == 'true' || needs.determine-driver-skips.outputs.sparksql-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: 'true'
@@ -1373,7 +1385,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -1381,7 +1394,7 @@ jobs:
be-tests-sqlite-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.sqlite-should-run == 'true' || needs.determine-driver-skips.outputs.sqlite-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: 'true'
@@ -1414,7 +1427,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -1422,7 +1436,7 @@ jobs:
be-tests-sqlserver:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.sqlserver-should-run == 'true' || needs.determine-driver-skips.outputs.sqlserver-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
@@ -1490,7 +1504,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -1505,7 +1520,7 @@ jobs:
# be-tests-starburst-ee:
# needs: determine-driver-skips
# if: ${{ !inputs.skip && !(needs.determine-driver-skips.outputs.skip == 'true') }}
# runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
# runs-on: ubuntu-latest
# timeout-minutes: 40
# env:
# CI: 'true'
@@ -1535,21 +1550,22 @@ jobs:
# input-path: ./target/junit/
# output-name: ${{ github.job }}
# bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
# role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
# aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
# aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
# aws-region: ${{ vars.AWS_REGION }}
# trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
login-to-ecr:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.vertica-should-run == 'true' || needs.determine-driver-skips.outputs.vertica-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
id-token: write
contents: read
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.CI_IAM_ROLE }}
role-session-name: GitHub_to_AWS_via_FederatedOIDC
@@ -1572,7 +1588,7 @@ jobs:
be-tests-vertica-ee:
needs: [determine-driver-skips, login-to-ecr]
if: ${{ needs.determine-driver-skips.outputs.vertica-should-run == 'true' || needs.determine-driver-skips.outputs.vertica-quarantine-conflict == 'true' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: 'true'
@@ -1615,7 +1631,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -1645,7 +1662,7 @@ jobs:
# TODO(rileythomp, 2025-08-20): Re-enable vertica tests once the docker image is updated
# - be-tests-vertica-ee
- be-tests-clickhouse-ee
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
name: drivers-tests-result
if: always() && !cancelled()

View File

@@ -21,7 +21,7 @@ on:
jobs:
build-matrix:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
outputs:
matrix: ${{ steps.matrix.outputs.config }}
@@ -47,7 +47,7 @@ jobs:
const inputSpecs = "${{ inputs.specs }}";
const inputChunks = Number(process.env.chunks);
const java = 21;
const defaultRunner = "${{ vars.DEFAULT_RUNNER_KEY }}";
const defaultRunner = "ubuntu-22.04";
const options = {
java,
defaultRunner,

View File

@@ -31,16 +31,11 @@ on:
type: boolean
required: false
default: true
fail_fast:
description: "Stop running remaining tests after the first failure"
type: boolean
required: false
default: false
jobs:
determine-test-type:
name: Determine test type
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
outputs:
type: ${{ steps.detect.outputs.type }}
@@ -58,7 +53,7 @@ jobs:
workflow-summary:
name: Stress test inputs
needs: [determine-test-type]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- name: Generate workflow summary
@@ -72,13 +67,12 @@ jobs:
echo '- `grep`: "${{ inputs.grep }}"' >> $GITHUB_STEP_SUMMARY
echo '- `qa_db`: "${{ inputs.qa_db }}"' >> $GITHUB_STEP_SUMMARY
echo '- `enable_network_throttling`: "${{ inputs.enable_network_throttling }}"' >> $GITHUB_STEP_SUMMARY
echo '- `fail_fast`: "${{ inputs.fail_fast }}"' >> $GITHUB_STEP_SUMMARY
echo '' >> $GITHUB_STEP_SUMMARY
echo 'triggered by: @${{ github.event.sender.login }}' >> $GITHUB_STEP_SUMMARY
stress-test-flake-fix:
needs: [determine-test-type]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 60
name: Stress test E2E flake fix
env:
@@ -150,13 +144,10 @@ jobs:
env:
GREP: ${{ github.event.inputs.grep }}
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
FAIL_FAST: ${{ inputs.fail_fast }}
SPEC: ${{ github.event.inputs.spec }}
BURN_IN: ${{ github.event.inputs.burn_in }}
run: |
node e2e/runner/run_cypress_ci.js ${{ needs.determine-test-type.outputs.type }} \
--spec "${SPEC}" \
--env burn="${BURN_IN}" \
--spec '${{ github.event.inputs.spec }}' \
--env burn=${{ github.event.inputs.burn_in }} \
--config-file e2e/support/cypress-stress-test.config.js
- name: Upload Cypress Artifacts upon failure

View File

@@ -21,7 +21,7 @@ on:
runner:
required: false
type: string
default: ${{ vars.DEFAULT_RUNNER_KEY }}
default: ubuntu-22.04
total_chunks: # number of chunks
required: false
type: number
@@ -166,7 +166,8 @@ jobs:
# Related to our custom upload to S3
output-name: e2e-${{ inputs.name }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
# Related to Trunk uploader
variant: e2e-tests

View File

@@ -24,7 +24,7 @@ jobs:
reset-e2e-test-comment:
if: ${{ github.event_name == 'pull_request' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Remove test results comment
@@ -75,7 +75,7 @@ jobs:
collect-timings:
name: Collect E2E Timings
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
needs: e2e-tests
if: always() && !cancelled() && github.ref == 'refs/heads/master'
@@ -138,7 +138,7 @@ jobs:
e2e-tests-result:
needs:
- e2e-tests
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
name: e2e-tests-result
if: always() && !cancelled()

View File

@@ -12,7 +12,7 @@ env:
jobs:
sdk-component-tests:
name: "SDK component tests (React ${{ matrix.react-version }})"
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 45
strategy:
matrix:
@@ -94,7 +94,8 @@ jobs:
input-path: ./target/junit
output-name: e2e-embedding-sdk-react-${{ matrix.react-version }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.run-tests.outcome }}
@@ -127,7 +128,7 @@ jobs:
await core.summary.addRaw(summary).write();
decide-target-ref:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
outputs:
target-ref: ${{ steps.get-target-ref.outputs.value }}
steps:
@@ -150,7 +151,7 @@ jobs:
sdk-component-tests-backward-compatibility:
name: "SDK component tests (Backward compatibility)"
needs: [decide-target-ref]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 45
env:
MB_RUN_MODE: "e2e"
@@ -247,7 +248,8 @@ jobs:
input-path: ./target/junit
output-name: e2e-embedding-sdk
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.run-tests.outcome }}

View File

@@ -12,7 +12,7 @@ env:
MB_EDITION: ee
jobs:
get-sample-apps-data:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
env:
# we must support the last two stable releases
@@ -94,7 +94,7 @@ jobs:
environment: ["production", "development"]
if: |
!cancelled() && needs.get-sample-apps-data.result == 'success'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 45
name: e2e-sample-app-${{ matrix.test_suite }}-tests-${{ matrix.environment }}-bundle
env:
@@ -106,8 +106,6 @@ jobs:
SAMPLE_APP_ENVIRONMENT: ${{ matrix.environment }}
permissions:
id-token: write
contents: read
actions: read
steps:
- uses: actions/checkout@v4
@@ -116,7 +114,7 @@ jobs:
# We have to use the latest version that does not have this issue https://github.com/docker/compose/pull/12752
- name: Set up Docker Compose
uses: docker/setup-compose-action@2fe291b7677a45ee1269ec56a42604c143505e7e # v1
uses: docker/setup-compose-action@v1
with:
version: latest
@@ -203,7 +201,7 @@ jobs:
if: |
!cancelled() && needs.get-sample-apps-data.result == 'success' &&
(github.ref == 'refs/heads/master' || github.base_ref == 'master')
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 45
name: e2e-sample-app-shoppy-e2e-tests-${{ matrix.environment }}-bundle
env:
@@ -215,8 +213,6 @@ jobs:
SAMPLE_APP_ENVIRONMENT: ${{ matrix.environment }}
permissions:
id-token: write
contents: read
actions: read
steps:
- uses: actions/checkout@v4
@@ -268,7 +264,7 @@ jobs:
!cancelled() && needs.get-sample-apps-data.result == 'success' &&
github.event_name == 'push' &&
github.ref == 'refs/heads/master'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 45
name: e2e-shoppy-synthetic-monitoring-tests
env:
@@ -281,7 +277,6 @@ jobs:
permissions:
id-token: write
contents: read
actions: read
steps:
- uses: actions/checkout@v4
@@ -359,7 +354,7 @@ jobs:
"angular-20-host-app-e2e",
]
environment: ["production", "development"]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 45
name: e2e-host-app-${{ matrix.test_suite }}-tests-${{ matrix.environment }}-bundle
env:
@@ -367,8 +362,6 @@ jobs:
HOST_APP_ENVIRONMENT: ${{ matrix.environment }}
permissions:
id-token: write
contents: read
actions: read
steps:
- uses: actions/checkout@v4

View File

@@ -10,14 +10,14 @@ on:
jobs:
files-changed:
name: Check which files changed
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
frontend_embedding_sdk_package_sources: ${{ steps.changes.outputs.frontend_embedding_sdk_package_sources }}
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
@@ -29,11 +29,11 @@ jobs:
!cancelled() &&
(needs.files-changed.outputs.frontend_embedding_sdk_package_sources == 'true')
name: Embedding SDK package release-notes/no-release-notes label reminder
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: jesusvasquez333/verify-pr-label-action@657d111bbbe13e22bbd55870f1813c699bde1401 # v1.4.0
- uses: jesusvasquez333/verify-pr-label-action@v1.4.0
id: verify-release-notes-labels
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'

View File

@@ -10,7 +10,7 @@ concurrency:
jobs:
build-sdk-package:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 25
steps:
- uses: actions/checkout@v4

View File

@@ -39,7 +39,7 @@ concurrency:
jobs:
embedding-sdk-cli-snippets-type-check:
if: inputs.cli-snippets-type-check && !inputs.skip
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
@@ -55,7 +55,7 @@ jobs:
embedding-sdk-docs-snippets-type-check:
if: inputs.docs-snippets-type-check && !inputs.skip
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
@@ -71,7 +71,7 @@ jobs:
embedding-sdk-api-documentation-generation-validation:
if: inputs.documentation-validation && !inputs.skip
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
@@ -131,7 +131,7 @@ jobs:
embedding-sdk-bundle-size-check:
if: inputs.bundle-size-check
continue-on-error: true
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 20
env:
BUNDLE_SIZE_THRESHOLD_PERCENT: 2
@@ -186,7 +186,7 @@ jobs:
- embedding-sdk-api-documentation-generation-validation
- embedding-sdk-component-tests
if: always() && !cancelled()
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
env:
needs: ${{ toJson(needs) }}

View File

@@ -7,7 +7,7 @@ on:
jobs:
on-escalation-label:
if: github.event.label.name == '.Escalation'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- name: Format issue title (escape quotes)
@@ -18,7 +18,7 @@ jobs:
core.setOutput('issue_title', ${{ toJson(github.event.issue.title) }}.replaceAll(/"/g, '\\"'));
- name: Send escalated issue ${{ github.event.issue.number }} to Slack
id: slack
uses: slackapi/slack-github-action@007b2c3c751a190b6f0f040e47ed024deaa72844 # v1.23.0
uses: slackapi/slack-github-action@v1.23.0
with:
payload: |
{

View File

@@ -19,7 +19,7 @@ on:
jobs:
workflow-summary:
name: Stress test inputs
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- name: Generate workflow summary
@@ -34,7 +34,7 @@ jobs:
echo 'triggered by: @${{ github.event.sender.login }}' >> $GITHUB_STEP_SUMMARY
frontend-unit-test-stress-test-flake-fix:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 60
name: Stress test frontend unit test flake fix
steps:
@@ -47,16 +47,11 @@ jobs:
run: bun run build:cljs
- name: Stress-test ${{ github.event.inputs.spec }} ${{ github.event.inputs.burn_in }} times
run: |
for ((i=1; i<=BURN_IN; i++)); do
for i in {1..${{ github.event.inputs.burn_in }}}; do
bun run jest --runInBand --ci --silent --no-cache \
--testPathPatterns "${SPEC}" \
--testNamePattern "${GREP}"
--testPathPatterns '${{ github.event.inputs.spec }}' \
--testNamePattern '${{ github.event.inputs.grep }}'
if [[ "$?" != 0 ]]; then
echo "Failed after $i attempts" && break;
fi
done
env:
BURN_IN: ${{ github.event.inputs.burn_in }}
SPEC: ${{ github.event.inputs.spec }}
GREP: ${{ github.event.inputs.grep }}

View File

@@ -27,7 +27,7 @@ concurrency:
jobs:
fe-lint:
if: ${{ !inputs.skip-lint }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
@@ -58,7 +58,7 @@ jobs:
fe-type-check:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
@@ -73,7 +73,7 @@ jobs:
fe-tests-unit:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 30
strategy:
fail-fast: false
@@ -103,14 +103,15 @@ jobs:
input-path: ./target/junit
output-name: frontend-unit
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.fe-tests.outcome }}
fe-tests-timezones:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
@@ -128,7 +129,7 @@ jobs:
- fe-tests-unit
- fe-tests-timezones
if: always() && !cancelled()
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
env:
needs: ${{ toJson(needs) }}

View File

@@ -24,7 +24,7 @@ on:
# TODO: Consider renaming the job in next milestones
jobs:
generative-query-test:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 90
name: Generative Query Test
env:
@@ -47,7 +47,7 @@ jobs:
run: clojure -X:dev:ci:test:ee:ee-dev :only '${{ inputs.test }}'
- name: Publish Test Report (JUnit)
uses: dorny/test-reporter@3eeb9fc888e82e8be2fb356bbeec2750231672bc # v1
uses: dorny/test-reporter@v1
if: failure()
with:
path: "target/junit/**/*_test.xml"

View File

@@ -14,14 +14,14 @@ concurrency:
jobs:
files-changed:
name: Check which files changed
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
i18n: ${{ steps.changes.outputs.i18n }}
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
@@ -30,7 +30,7 @@ jobs:
verify-i18n-files:
needs: files-changed
if: needs.files-changed.outputs.i18n == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v4

View File

@@ -7,8 +7,7 @@ on:
jobs:
js-stats:
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4

View File

@@ -6,7 +6,7 @@ on:
jobs:
add-issue-references:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

View File

@@ -21,7 +21,7 @@ on:
jobs:
detect-changed-stories:
name: Detect changed stories
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
outputs:
story_files: ${{ steps.detect.outputs.story_files }}
@@ -84,40 +84,32 @@ jobs:
name: Summary
needs: detect-changed-stories
if: needs.detect-changed-stories.outputs.should_run == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- name: Generate workflow summary
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
STORY_FILES: ${{ needs.detect-changed-stories.outputs.story_files }}
BURN_IN: ${{ inputs.burn_in || 50 }}
EVENT_NAME: ${{ github.event_name }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_ACTOR: ${{ github.event.pull_request.user.login }}
ACTOR: ${{ github.actor }}
run: |
echo '## Loki Stress Test' >> $GITHUB_STEP_SUMMARY
echo '' >> $GITHUB_STEP_SUMMARY
echo "**Branch:** \`${BRANCH_NAME}\`" >> $GITHUB_STEP_SUMMARY
echo '**Branch:** `${{ github.head_ref || github.ref_name }}`' >> $GITHUB_STEP_SUMMARY
echo '' >> $GITHUB_STEP_SUMMARY
echo '**Story files:**' >> $GITHUB_STEP_SUMMARY
echo "${STORY_FILES}" | tr ',' '\n' | while read -r file; do
echo '${{ needs.detect-changed-stories.outputs.story_files }}' | tr ',' '\n' | while read -r file; do
echo "- \`$file\`" >> $GITHUB_STEP_SUMMARY
done
echo '' >> $GITHUB_STEP_SUMMARY
echo "**Burn-in:** ${BURN_IN} runs" >> $GITHUB_STEP_SUMMARY
echo '**Burn-in:** ${{ inputs.burn_in || 50 }} runs' >> $GITHUB_STEP_SUMMARY
echo '' >> $GITHUB_STEP_SUMMARY
if [[ "${EVENT_NAME}" == "pull_request" ]]; then
echo "Triggered by PR #${PR_NUMBER} from @${PR_ACTOR}" >> $GITHUB_STEP_SUMMARY
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo 'Triggered by PR #${{ github.event.pull_request.number }} from @${{ github.event.pull_request.user.login }}' >> $GITHUB_STEP_SUMMARY
else
echo "Triggered manually by @${ACTOR}" >> $GITHUB_STEP_SUMMARY
echo 'Triggered manually by @${{ github.actor }}' >> $GITHUB_STEP_SUMMARY
fi
stress-test-loki:
needs: detect-changed-stories
if: needs.detect-changed-stories.outputs.should_run == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 60
name: Stress test Loki visual tests
services:

View File

@@ -7,7 +7,7 @@ on:
jobs:
check-label-and-update-snapshot:
if: contains(github.event.pull_request.labels.*.name, 'loki-update')
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4

View File

@@ -7,7 +7,7 @@ on:
jobs:
files-changed:
name: Check which files changed
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
frontend_ci: ${{ steps.changes.outputs.frontend_ci }}
@@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
@@ -25,7 +25,7 @@ jobs:
visual-test:
needs: files-changed
if: needs.files-changed.outputs.frontend_ci == 'true' || needs.files-changed.outputs.frontend_sources == 'true' || needs.files-changed.outputs.frontend_loki_ci == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
services:
docker:
image: docker:19.03.12

View File

@@ -6,7 +6,7 @@ on:
jobs:
# run mage tests even if the rest of be isnt needed
mage-tests:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
name: Mage
steps:
- uses: actions/checkout@v4

View File

@@ -6,7 +6,7 @@ on:
- labeled
jobs:
on-issue-labeled:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
if: |
contains(github.event.issue.labels.*.name, 'Type:New Feature')
@@ -19,7 +19,7 @@ jobs:
core.setOutput('issue_title', ${{ toJson(github.event.issue.title) }}.replaceAll(/"/g, '\\"'));
- name: Send the issue ${{ github.event.issue.number }} to Slack
id: slack
uses: slackapi/slack-github-action@70cd7be8e40a46e8b0eced40b0de447bdb42f68e # v1.26.0
uses: slackapi/slack-github-action@v1.26.0
with:
payload: |
{

View File

@@ -11,7 +11,7 @@ on:
- src/metabase/lib/js.cljs
jobs:
mbql-library-changelog-check:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
if: ${{ !contains( github.event.pull_request.labels.*.name, '.metabase-lib/no-change' ) }}
steps:
# - uses: jesusvasquez333/verify-pr-label-action@v1.4.0

View File

@@ -6,13 +6,11 @@ on:
- 'master'
- 'release-**'
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
jobs:
lint-migrations:
if: github.event.action != 'labeled' && github.event.action != 'unlabeled'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
@@ -20,19 +18,3 @@ jobs:
uses: ./.github/actions/prepare-backend
- name: Verify Liquibase Migrations
run: ./bin/mage lint-migrations
check-migration-versions:
if: github.event_name == 'pull_request'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
with:
filter: blob:none
fetch-depth: 0
- name: Check migration versions
env:
BASE_REF: ${{ github.base_ref }}
CURRENT_VERSION: ${{ vars.CURRENT_VERSION }}
PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }}
run: bin/check-migration-versions

View File

@@ -8,16 +8,10 @@ concurrency:
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
cancel-in-progress: true
permissions:
id-token: write
contents: read
checks: write
actions: read
jobs:
# Only run if the PR has the minimal-tests label
check-label:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 1
outputs:
should-run: ${{ steps.check.outputs.result }}
@@ -35,7 +29,7 @@ jobs:
postgres-app-db-test:
needs: check-label
if: needs.check-label.outputs.should-run == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 40
env:
CI: "true"
@@ -76,7 +70,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -85,7 +80,7 @@ jobs:
postgres-driver-test:
needs: check-label
if: needs.check-label.outputs.should-run == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: "true"
@@ -123,7 +118,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -132,7 +128,7 @@ jobs:
frontend-unit-tests:
needs: check-label
if: needs.check-label.outputs.should-run == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 30
env:
JEST_JUNIT_OUTPUT_DIR: ./target/junit
@@ -155,7 +151,8 @@ jobs:
input-path: ./target/junit
output-name: frontend-unit
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.run-tests.outcome }}
@@ -166,7 +163,7 @@ jobs:
- postgres-app-db-test
- postgres-driver-test
- frontend-unit-tests
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
name: minimal-tests-result
if: always() && !cancelled()

View File

@@ -7,12 +7,11 @@ on:
jobs:
module-boundaries-stats:
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
- uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install --frozen-lockfile
- name: get module boundary stats
@@ -21,7 +20,6 @@ jobs:
NAMED_MODULES=$(node --input-type=module -e "
import { elements } from './frontend/lint/module-boundaries.mjs';
const named = elements.filter(e => !['shared/other', 'app/misc', 'other'].includes(e.type));
console.log(named.length);
")
NAMED_DIRS=$(node --input-type=module -e "
@@ -31,7 +29,6 @@ jobs:
const m = el.pattern.match(/^frontend\/src\/metabase\/(\w[\w-]*)\//)
if (m) dirs.add(m[1]);
}
for (const d of dirs) console.log(d);
")
TOTAL_DIRS=$(ls -d frontend/src/metabase/*/ | xargs -I{} basename {} | wc -l | tr -d ' ')
NAMED_COUNT=$(echo "$NAMED_DIRS" | grep -c . || true)

View File

@@ -10,7 +10,7 @@ concurrency:
jobs:
check-openapi-specs:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
if: contains(github.event.pull_request.labels.*.name, 'openapi-self-healing')
steps:

View File

@@ -14,14 +14,14 @@ concurrency:
jobs:
files-changed:
name: Check which files changed
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
openapi: ${{ steps.changes.outputs.openapi }}
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
@@ -30,7 +30,7 @@ jobs:
validate-openapi:
needs: files-changed
if: needs.files-changed.outputs.openapi == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4

View File

@@ -7,7 +7,7 @@ on:
jobs:
optimize-images:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
if: ${{ contains(github.event.pull_request.labels.*.name,'Type:Documentation') }}
steps:
- name: Checkout repository

View File

@@ -5,7 +5,7 @@ on:
workflow_call:
jobs:
build:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.full_name == github.repository
name: Build Metabase Docker image
timeout-minutes: 60
@@ -17,13 +17,13 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.PR_ENV_IAM_ROLE }}
role-session-name: GitHub_to_AWS_via_FederatedOIDC
aws-region: us-east-1
- name: Login to Amazon ECR
uses: aws-actions/amazon-ecr-login@183a1442edf41672e66566b7fc560e297a290896 # v2
uses: aws-actions/amazon-ecr-login@v2
with:
registries: "${{ secrets.PR_ENV_AWS_ACCOUNT_ID }}"
- name: Retrieve uberjar artifact for ee
@@ -38,7 +38,7 @@ jobs:
jar xf target/uberjar/metabase.jar
mv target/uberjar/metabase.jar bin/docker/metabase.jar
- name: Build container
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
uses: docker/build-push-action@v6
with:
context: bin/docker/
platforms: linux/amd64
@@ -47,7 +47,7 @@ jobs:
push: true
launch_perf_test:
needs: [ build ]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
name: Launch Perf Test
permissions:
id-token: write
@@ -56,7 +56,7 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
- name: Tailscale
uses: tailscale/github-action@4e4c49acaa9818630ce0bd7a564372c17e33fb4d # v2
uses: tailscale/github-action@v2
with:
oauth-client-id: ${{ secrets.PR_ENV_TAILSCALE_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.PR_ENV_TAILSCALE_OAUTH_SECRET }}
@@ -67,14 +67,12 @@ jobs:
id: create-oidc-token
shell: bash
run: |
export OIDC_URL_WITH_AUDIENCE="$ACTIONS_ID_TOKEN_REQUEST_URL&audience=${PR_ENV_K8S_AUDIENCE}"
export OIDC_URL_WITH_AUDIENCE="$ACTIONS_ID_TOKEN_REQUEST_URL&audience=${{ secrets.PR_ENV_K8S_AUDIENCE }}"
IDTOKEN=$(curl -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" -H "Accept: application/json; api-version=2.0" "$OIDC_URL_WITH_AUDIENCE" | jq -r .value)
echo "::add-mask::${IDTOKEN}"
echo "idToken=${IDTOKEN}" >>$GITHUB_OUTPUT
env:
PR_ENV_K8S_AUDIENCE: ${{ secrets.PR_ENV_K8S_AUDIENCE }}
- name: Setup Kube Context
uses: azure/k8s-set-context@0b53301dcc7ddd3f6d35f97fb67228ac4e5ab2fd # v2
uses: azure/k8s-set-context@v2
with:
method: kubeconfig
kubeconfig: |
@@ -97,7 +95,7 @@ jobs:
namespace: default
user: oidc-token
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.PR_ENV_IAM_ROLE }}
role-session-name: GitHub_to_AWS_via_FederatedOIDC
@@ -110,7 +108,7 @@ jobs:
id: split
run: echo "::set-output name=fragment::${SHA:5}"
- name: Render Deployment YAML
uses: nowactions/envsubst@c4b8e3977354d294659a7ec164279ce8fba5c2e1 # v1
uses: nowactions/envsubst@v1
with:
input: ./perf-test-pr.yml.tmpl
output: ./perf-test-pr.yml

View File

@@ -14,7 +14,7 @@ on:
jobs:
approve:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
environment: pr-env-admin
steps:
- name: Approved

View File

@@ -19,7 +19,7 @@ env:
jobs:
destroy_pr:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
name: PR Review ENV Destroy
permissions:
id-token: write
@@ -28,7 +28,7 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
- name: Tailscale
uses: tailscale/github-action@4e4c49acaa9818630ce0bd7a564372c17e33fb4d # v2
uses: tailscale/github-action@v2
with:
oauth-client-id: ${{ secrets.PR_ENV_TAILSCALE_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.PR_ENV_TAILSCALE_OAUTH_SECRET }}
@@ -39,14 +39,12 @@ jobs:
id: create-oidc-token
shell: bash
run: |
export OIDC_URL_WITH_AUDIENCE="$ACTIONS_ID_TOKEN_REQUEST_URL&audience=${PR_ENV_K8S_AUDIENCE}"
export OIDC_URL_WITH_AUDIENCE="$ACTIONS_ID_TOKEN_REQUEST_URL&audience=${{ secrets.PR_ENV_K8S_AUDIENCE }}"
IDTOKEN=$(curl -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" -H "Accept: application/json; api-version=2.0" "$OIDC_URL_WITH_AUDIENCE" | jq -r .value)
echo "::add-mask::${IDTOKEN}"
echo "idToken=${IDTOKEN}" >>$GITHUB_OUTPUT
env:
PR_ENV_K8S_AUDIENCE: ${{ secrets.PR_ENV_K8S_AUDIENCE }}
- name: Setup Kube Context
uses: azure/k8s-set-context@0b53301dcc7ddd3f6d35f97fb67228ac4e5ab2fd # v2
uses: azure/k8s-set-context@v2
with:
method: kubeconfig
kubeconfig: |
@@ -75,7 +73,7 @@ jobs:
kubectl delete ns hosting-pr${{ env.PR_NUMBER }}
- name: Setup Helm
if: ${{ inputs.self_hosting }}
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4
uses: azure/setup-helm@v4
with:
version: 'latest'
- name: Destroy PR Review ENV (self-hosting)
@@ -89,15 +87,9 @@ jobs:
sudo apt-get install -y postgresql-client
- name: Drop app database if exists
run: |
PGPASSWORD="${PR_ENV_DB_PASSWORD}" \
PGPASSWORD='${{ secrets.PR_ENV_DB_PASSWORD }}' \
psql \
-h "${PR_ENV_DB_HOST}" \
-U "${PR_ENV_DB_USER}" \
-d "${PR_ENV_DB_NAME}" \
-h ${{ secrets.PR_ENV_DB_HOST }} \
-U ${{ secrets.PR_ENV_DB_USER }} \
-d ${{ secrets.PR_ENV_DB_NAME }} \
-c "DROP DATABASE IF EXISTS hosting_pr${{ env.PR_NUMBER }};"
env:
PR_ENV_DB_PASSWORD: ${{ secrets.PR_ENV_DB_PASSWORD }}
PR_ENV_DB_HOST: ${{ secrets.PR_ENV_DB_HOST }}
PR_ENV_DB_USER: ${{ secrets.PR_ENV_DB_USER }}
PR_ENV_DB_NAME: ${{ secrets.PR_ENV_DB_NAME }}

View File

@@ -16,7 +16,7 @@ on:
default: false
jobs:
build:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.full_name == github.repository
name: Build Metabase Docker image
timeout-minutes: 60
@@ -28,13 +28,13 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.PR_ENV_IAM_ROLE }}
role-session-name: GitHub_to_AWS_via_FederatedOIDC
aws-region: us-east-1
- name: Login to Amazon ECR
uses: aws-actions/amazon-ecr-login@183a1442edf41672e66566b7fc560e297a290896 # v2
uses: aws-actions/amazon-ecr-login@v2
with:
registries: "${{ secrets.PR_ENV_AWS_ACCOUNT_ID }}"
- name: Retrieve uberjar artifact for ee
@@ -49,7 +49,7 @@ jobs:
jar xf target/uberjar/metabase.jar
mv target/uberjar/metabase.jar bin/docker/metabase.jar
- name: Build container
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
uses: docker/build-push-action@v6
with:
context: bin/docker/
platforms: linux/amd64
@@ -58,7 +58,7 @@ jobs:
push: true
deploy_pr:
needs: [build]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
name: PR Review ENV
permissions:
id-token: write
@@ -67,7 +67,7 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
- name: Tailscale
uses: tailscale/github-action@4e4c49acaa9818630ce0bd7a564372c17e33fb4d # v2
uses: tailscale/github-action@v2
with:
oauth-client-id: ${{ secrets.PR_ENV_TAILSCALE_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.PR_ENV_TAILSCALE_OAUTH_SECRET }}
@@ -78,14 +78,12 @@ jobs:
id: create-oidc-token
shell: bash
run: |
export OIDC_URL_WITH_AUDIENCE="$ACTIONS_ID_TOKEN_REQUEST_URL&audience=${PR_ENV_K8S_AUDIENCE}"
export OIDC_URL_WITH_AUDIENCE="$ACTIONS_ID_TOKEN_REQUEST_URL&audience=${{ secrets.PR_ENV_K8S_AUDIENCE }}"
IDTOKEN=$(curl -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" -H "Accept: application/json; api-version=2.0" "$OIDC_URL_WITH_AUDIENCE" | jq -r .value)
echo "::add-mask::${IDTOKEN}"
echo "idToken=${IDTOKEN}" >>$GITHUB_OUTPUT
env:
PR_ENV_K8S_AUDIENCE: ${{ secrets.PR_ENV_K8S_AUDIENCE }}
- name: Setup Kube Context
uses: azure/k8s-set-context@0b53301dcc7ddd3f6d35f97fb67228ac4e5ab2fd # v2
uses: azure/k8s-set-context@v2
with:
method: kubeconfig
kubeconfig: |
@@ -108,7 +106,7 @@ jobs:
namespace: default
user: oidc-token
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.PR_ENV_IAM_ROLE }}
role-session-name: GitHub_to_AWS_via_FederatedOIDC
@@ -119,24 +117,19 @@ jobs:
sudo apt-get install -y postgresql-client
- name: Create app database if not exists
run: |
export PGPASSWORD="${PR_ENV_DB_PASSWORD}"
export PGUSER="${PR_ENV_DB_USER}"
export PGHOST="${PR_ENV_DB_HOST}"
export PGDATABASE="${PR_ENV_DB_NAME}"
export PGPASSWORD='${{ secrets.PR_ENV_DB_PASSWORD }}'
export PGUSER=${{ secrets.PR_ENV_DB_USER }}
export PGHOST=${{ secrets.PR_ENV_DB_HOST }}
export PGDATABASE=${{ secrets.PR_ENV_DB_NAME }}
psql -tc "SELECT 1 FROM pg_database WHERE datname = 'hosting_pr${{ github.event.number }}'" \
| grep -q 1 \
|| psql -c "CREATE DATABASE hosting_pr${{ github.event.number }}"
env:
PR_ENV_DB_PASSWORD: ${{ secrets.PR_ENV_DB_PASSWORD }}
PR_ENV_DB_USER: ${{ secrets.PR_ENV_DB_USER }}
PR_ENV_DB_HOST: ${{ secrets.PR_ENV_DB_HOST }}
PR_ENV_DB_NAME: ${{ secrets.PR_ENV_DB_NAME }}
- name: Download Deployment YAML template
if: ${{ !inputs.self_hosting }}
run: aws s3 cp s3://metabase-pr-env/metabase.yml.tmpl ./metabase.yml.tmpl
- name: Render Deployment YAML
if: ${{ !inputs.self_hosting }}
uses: nowactions/envsubst@c4b8e3977354d294659a7ec164279ce8fba5c2e1 # v1
uses: nowactions/envsubst@v1
with:
input: ./metabase.yml.tmpl
output: ./metabase.yml
@@ -155,7 +148,7 @@ jobs:
run: aws s3 cp s3://metabase-pr-env/values.yaml.tmpl ./values.yaml.tmpl
- name: Render Helm values (self-hosting)
if: ${{ inputs.self_hosting }}
uses: nowactions/envsubst@c4b8e3977354d294659a7ec164279ce8fba5c2e1 # v1
uses: nowactions/envsubst@v1
with:
input: ./values.yaml.tmpl
output: ./values.yaml
@@ -175,18 +168,15 @@ jobs:
- name: Setup Helm
if: ${{ inputs.self_hosting }}
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4
uses: azure/setup-helm@v4
with:
version: 'latest'
- name: Login to Quay.io
if: ${{ inputs.self_hosting }}
run: |
helm registry login quay.io \
--username "${QUAY_USERNAME}" \
--password "${QUAY_PASSWORD}"
env:
QUAY_USERNAME: ${{ secrets.QUAY_USERNAME }}
QUAY_PASSWORD: ${{ secrets.QUAY_PASSWORD }}
--username ${{ secrets.QUAY_USERNAME }} \
--password ${{ secrets.QUAY_PASSWORD }}
- name: Deploy PR Review ENV (self-hosting)
if: ${{ inputs.self_hosting }}
run: |
@@ -198,10 +188,10 @@ jobs:
--atomic \
--timeout 10m
preview_links:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
needs: [deploy_pr]
steps:
- uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2
- uses: marocchino/sticky-pull-request-comment@v2
with:
recreate: true
message: |

View File

@@ -25,7 +25,7 @@ on:
jobs:
test-mode-config:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
outputs:
run_mode: ${{ fromJson(steps.config.outputs.result).runMode }}
@@ -65,7 +65,7 @@ jobs:
});
release-artifact:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
strategy:
matrix:
@@ -110,7 +110,7 @@ jobs:
check-uberjar-health:
needs: [release-artifact]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
name: Is ${{ matrix.edition }} (java ${{ matrix.java-version }}) healthy?
timeout-minutes: 10
strategy:
@@ -136,7 +136,7 @@ jobs:
run: while ! curl -s 'http://localhost:3000/api/health' | grep '{"status":"ok"}'; do sleep 1; done
run-sanity-check:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 30
needs: [test-mode-config, release-artifact]
strategy:
@@ -258,8 +258,14 @@ jobs:
tests-complete-message:
if: always()
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
needs: [run-sanity-check, check-uberjar-health, containerize-ee, containerize-oss]
runs-on: ubuntu-22.04
needs:
[
run-sanity-check,
check-uberjar-health,
containerize-ee,
containerize-oss,
]
timeout-minutes: 5
steps:
- uses: actions/checkout@v4

View File

@@ -18,14 +18,14 @@ on:
jobs:
files-changed:
name: Check which files changed
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
backend_presto_kerberos: ${{ steps.changes.outputs.backend_presto_kerberos }}
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
@@ -34,7 +34,7 @@ jobs:
run-presto-kerberos-test:
needs: files-changed
if: needs.files-changed.outputs.backend_presto_kerberos == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 40
steps:
- name: Install babashka

View File

@@ -10,7 +10,7 @@ jobs:
external-reminder:
name: External PR Helper
if: ${{ github.event.pull_request.head.repo.full_name != github.repository }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
permissions:
pull-requests: write

View File

@@ -7,41 +7,38 @@ on:
jobs:
notify-querying-on-call:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
if: |
(github.event.label.name == 'Priority:P0' || github.event.label.name == 'Priority:P1' || github.event.label.name == '.Escalation') &&
contains(github.event.issue.labels.*.name, '.Team/Querying')
steps:
- name: Setting title
uses: actions/github-script@v7
id: vars
with:
script: |
core.setOutput('issue_title', ${{ toJson(github.event.issue.title) }}.replaceAll(/"/g, '\\"'));
- name: Trigger PagerDuty Incident
env:
ROUTING_KEY: ${{ secrets.QUERYING_PAGERDUTY_INTEGRATION_KEY }}
ISSUE_TITLE: ${{ github.event.issue.title }}
LABEL_NAME: ${{ github.event.label.name }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
ISSUE_URL: ${{ github.event.issue.html_url }}
REPO: ${{ github.repository }}
ALL_LABELS: ${{ join(github.event.issue.labels.*.name, ', ') }}
run: |
payload=$(jq -n \
--arg rk "$ROUTING_KEY" \
--arg dk "github-issue-$ISSUE_NUMBER" \
--arg sum "[$LABEL_NAME] $ISSUE_TITLE" \
--arg src "GitHub Issues - $REPO" \
--arg lbl "$ALL_LABELS" \
--arg url "$ISSUE_URL" \
'{
routing_key: $rk,
event_action: "trigger",
dedup_key: $dk,
payload: {
summary: $sum,
source: $src,
severity: "critical",
custom_details: { Labels: $lbl }
},
links: [{ href: $url, text: "View GitHub Issue" }]
}')
curl -X POST https://events.pagerduty.com/v2/enqueue \
-H 'Content-Type: application/json' \
-d "$payload"
-d '{
"routing_key": "${{ secrets.QUERYING_PAGERDUTY_INTEGRATION_KEY }}",
"event_action": "trigger",
"dedup_key": "github-issue-${{ github.event.issue.number }}",
"payload": {
"summary": "[${{ github.event.label.name }}] ${{ steps.vars.outputs.issue_title }}",
"source": "GitHub Issues - ${{ github.repository }}",
"severity": "critical",
"custom_details": {
"Labels": "${{ join(github.event.issue.labels.*.name, ', ') }}"
}
},
"links": [
{
"href": "${{ github.event.issue.html_url }}",
"text": "View GitHub Issue"
}
]
}'

View File

@@ -1,68 +0,0 @@
name: Release Custom Viz Package
run-name: Release @metabase/custom-viz v${{ inputs.version }} from ${{ inputs.branch }}
on:
workflow_dispatch:
inputs:
branch:
description: "Branch to release from"
type: string
required: true
default: "custom-viz"
version:
description: "Version to publish (e.g. 0.1.0)"
type: string
required: true
npm_tag:
description: "NPM dist-tag"
type: choice
required: true
default: "latest"
options:
- latest
- next
- canary
jobs:
build-and-publish:
runs-on: ubuntu-22.04
timeout-minutes: 20
defaults:
run:
working-directory: frontend/src/custom-viz
steps:
- name: Check out the code
uses: actions/checkout@v4
with:
ref: ${{ inputs.branch }}
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Setup npm registry auth
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
registry-url: "https://registry.npmjs.org"
- name: Set package version
run: npm version ${{ inputs.version }} --no-git-tag-version
- name: Build package
run: bun run build
- name: Publish to NPM
run: npm publish --tag ${{ inputs.npm_tag }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_RELEASE_TOKEN }}
- name: Generate workflow summary
run: |
tee -a $GITHUB_STEP_SUMMARY << EOF
## Published @metabase/custom-viz
- **Version**: ${{ inputs.version }}
- **Tag**: ${{ inputs.npm_tag }}
- **Branch**: ${{ inputs.branch }}
- **Triggered by**: @${{ github.event.sender.login }}
EOF

View File

@@ -21,7 +21,7 @@ concurrency:
jobs:
workflow-summary:
name: Log inputs
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- name: Generate workflow summary
@@ -37,7 +37,7 @@ jobs:
send-slack-notification-start:
name: "Send Slack notification: SDK release started"
needs: determine-sdk-version
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
outputs:
slackMessageId: ${{ steps.send-slack-message-start.outputs.result }}
@@ -96,7 +96,7 @@ jobs:
"publish-npm",
"git-tag",
]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
env:
slackMessageId: ${{ needs.send-slack-notification-start.outputs.slackMessageId }}
@@ -134,7 +134,7 @@ jobs:
name: "Send Slack notification: SDK release successful"
needs:
["determine-sdk-version", "send-slack-notification-start", "publish-npm"]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
env:
slackMessageId: ${{ needs.send-slack-notification-start.outputs.slackMessageId }}
@@ -168,7 +168,7 @@ jobs:
});
determine-sdk-version:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 20
outputs:
sdk_version: ${{ fromJson(steps.new-sdk-version.outputs.result).version }}
@@ -219,7 +219,7 @@ jobs:
check-git-tag:
needs: determine-sdk-version
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 20
env:
tag: embedding-sdk-${{ needs.determine-sdk-version.outputs.sdk_version }}
@@ -243,7 +243,7 @@ jobs:
test:
needs: check-git-tag
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
- name: Check out the code using the provided branch
@@ -262,7 +262,7 @@ jobs:
build-sdk:
needs: [test, determine-sdk-version]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
- name: Check out the code using the provided branch
@@ -297,7 +297,7 @@ jobs:
publish-npm:
needs: [build-sdk, determine-sdk-version]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 20
env:
sdk_version: ${{ needs.determine-sdk-version.outputs.sdk_version }}
@@ -383,14 +383,12 @@ jobs:
- name: Publish to NPM
working-directory: sdk
run: |
echo //registry.npmjs.org/:_authToken="${NPM_RELEASE_TOKEN}" > .npmrc
echo //registry.npmjs.org/:_authToken=${{ secrets.NPM_RELEASE_TOKEN }} > .npmrc
TAG="${{ steps.compute-tag.outputs.masterTag }}"
echo "Resolved npm tag: $TAG"
npm publish --tag "$TAG"
env:
NPM_RELEASE_TOKEN: ${{ secrets.NPM_RELEASE_TOKEN }}
# ⚠️ This step should only be executed on the latest stable (gold) release branch.
# Only uncomment this when the new release branch becomes stable (gold).
# - name: Add `latest` tag to the latest release branch (`release-x.55.x`) deployment
@@ -400,7 +398,7 @@ jobs:
git-tag:
needs: [publish-npm, determine-sdk-version]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 20
env:
tag: embedding-sdk-${{ needs.determine-sdk-version.outputs.sdk_version }}

View File

@@ -21,21 +21,18 @@ on:
type: number # needs to be a number to pass variables
required: true
permissions:
id-token: write
contents: read
jobs:
update-release-log:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
# don't run this workflow for forks
if: ${{ github.event_name != 'push' || github.repository == 'metabase/metabase' }}
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.CI_RELEASE_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_S3_RELEASE_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_S3_RELEASE_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- uses: actions/checkout@v4
with:

View File

@@ -15,14 +15,14 @@ on:
jobs:
check-milestone:
permissions: write-all
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Install bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -11,7 +11,7 @@ on:
jobs:
preview-release-notes:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- name: Fail early on the incorrect version format

View File

@@ -5,29 +5,29 @@ on:
workflow_dispatch:
inputs:
version:
description: "Major Metabase version (e.g. 45, 52, 68)"
description: 'Major Metabase version (e.g. 45, 52, 68)'
type: number
required: true
override_sha:
description: DANGEROUSLY allow releasing from this commit sha, regardless of the state of CI (can be empty)
type: string
required: false
default: ""
default: ''
schedule:
- cron: "0 21 * * 1-5" # every weekday at 4 pm EST/5 pm EDT
- cron: '0 21 * * 1-5' # every weekday at 4 pm EST/5 pm EDT
jobs:
auto-patch-trigger:
# don't run this workflow on a cron for forks
if: ${{ github.event_name != 'schedule' || (github.repository == 'metabase/metabase' && vars.ENABLE_AUTO_PATCH == 'true') }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Install bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -9,7 +9,7 @@ jobs:
check-release-status:
# don't run this workflow on a cron for forks
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
@@ -44,7 +44,7 @@ jobs:
});
open-backport-reminder:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4

View File

@@ -53,14 +53,9 @@ on:
type: boolean
default: false
permissions:
id-token: write
contents: read
actions: read
jobs:
green-check-stub:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 2
steps:
- name: Stub
@@ -68,7 +63,7 @@ jobs:
check-version:
# skips everything if the tag_name is 'none' because all later jobs depend on this job
if: ${{ inputs.tag_name != 'none' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
outputs:
ee: ${{ fromJson(steps.canonical_version.outputs.result).ee }}
@@ -143,7 +138,7 @@ jobs:
throw new Error("No edition selected to tag");
copy-to-s3:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
needs: check-version
timeout-minutes: 5
strategy:
@@ -151,9 +146,10 @@ jobs:
edition: ${{ fromJson(needs.check-version.outputs.edition_matrix) }}
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.CI_RELEASE_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_S3_RELEASE_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_S3_RELEASE_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- name: Determine the source path
uses: actions/github-script@v7
@@ -225,7 +221,7 @@ jobs:
fi
tag-docker-image:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
needs: check-version
timeout-minutes: 5
strategy:
@@ -247,7 +243,7 @@ jobs:
fi
- name: Login to Docker Hub
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_RELEASE_USERNAME }}
password: ${{ secrets.DOCKERHUB_RELEASE_TOKEN }}
@@ -261,7 +257,7 @@ jobs:
push-git-tags:
permissions: write-all
needs: check-version
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
env:
GH_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
@@ -292,7 +288,7 @@ jobs:
update-version-info:
if: ${{ !inputs.dot-x-tag }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
needs: check-version
timeout-minutes: 5
strategy:
@@ -303,9 +299,10 @@ jobs:
AWS_REGION: ${{ vars.AWS_REGION }}
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.CI_RELEASE_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_S3_RELEASE_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_S3_RELEASE_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- uses: actions/checkout@v4
with:

View File

@@ -14,14 +14,14 @@ concurrency:
jobs:
files-changed:
name: Check which files changed
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
release_source: ${{ steps.changes.outputs.release_source }}
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
@@ -30,14 +30,14 @@ jobs:
release-type-check:
needs: files-changed
if: needs.files-changed.outputs.release_source == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: "release"
- name: Install bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ secrets.GITHUB_TOKEN }}
@@ -49,14 +49,14 @@ jobs:
release-tests-unit:
needs: files-changed
if: needs.files-changed.outputs.release_source == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: "release"
- name: Install bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ secrets.GITHUB_TOKEN }}
@@ -68,14 +68,14 @@ jobs:
release-test-build:
needs: files-changed
if: needs.files-changed.outputs.release_source == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: "release"
- name: Install bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -46,15 +46,9 @@ on:
type: boolean
default: false
permissions:
id-token: write
contents: read
actions: read
checks: write
jobs:
check-version:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
outputs:
ee: ${{ fromJson(steps.canonical_version.outputs.result).ee }}
@@ -110,7 +104,7 @@ jobs:
return versions
publish-start-message:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
needs: [check-version]
timeout-minutes: 5
steps:
@@ -141,7 +135,7 @@ jobs:
download-uberjar:
needs: check-version
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
strategy:
matrix:
@@ -184,7 +178,7 @@ jobs:
./version.properties
upload-to-s3:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
needs: download-uberjar
timeout-minutes: 15
strategy:
@@ -192,9 +186,10 @@ jobs:
edition: [oss, ee]
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.CI_RELEASE_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_S3_RELEASE_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_S3_RELEASE_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- uses: actions/checkout@v4
with:
@@ -235,7 +230,7 @@ jobs:
--paths "/${{ steps.version_path.outputs.result }}/*"
verify-s3-download:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
needs: upload-to-s3
timeout-minutes: 15
strategy:
@@ -292,7 +287,7 @@ jobs:
push-tags:
permissions: write-all
needs: [verify-s3-download, containerize-oss, containerize-ee, check-version]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
@@ -325,7 +320,7 @@ jobs:
get-extra-tags:
needs: [ check-version ]
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
outputs:
extra_tags: ${{ steps.taglist.outputs.extra_tags }}
steps:
@@ -376,7 +371,7 @@ jobs:
trigger-cloud-issues:
if: ${{ !inputs.auto }}
needs: push-tags
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
@@ -428,7 +423,7 @@ jobs:
needs:
- containerize-ee
- verify-s3-download
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/github-script@v7
@@ -451,7 +446,7 @@ jobs:
draft-release-notes:
if: ${{ !inputs.auto }}
needs: add-extra-tags
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 15
permissions: write-all
env:
@@ -519,7 +514,7 @@ jobs:
}).catch(console.warn);
publish-version-info:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
needs: [push-tags, check-version]
timeout-minutes: 15
strategy:
@@ -535,9 +530,10 @@ jobs:
echo "skipping version info update for nightly patch"
exit 0
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.CI_RELEASE_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_S3_RELEASE_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_S3_RELEASE_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- uses: actions/checkout@v4
with:
@@ -594,7 +590,7 @@ jobs:
tag_oss: true
publish-complete-message:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
needs: [set-release-channel, add-extra-tags]
timeout-minutes: 5
steps:
@@ -627,7 +623,7 @@ jobs:
manage-milestones:
if: ${{ !inputs.auto }}
permissions: write-all
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
needs: [draft-release-notes, publish-version-info] # this will ensure that the milestone stays open until the release notes are published
timeout-minutes: 15
steps:

View File

@@ -18,13 +18,14 @@ on:
jobs:
repro-bot:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 60
permissions:
contents: read
issues: read
id-token: write
if: |
(github.event_name == 'push') ||
(github.event_name == 'issues' && github.event.label.name == '.Run Repro Bot' && github.event.issue.state == 'open') ||
(github.event_name == 'workflow_dispatch')
@@ -33,15 +34,13 @@ jobs:
id: issue
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
ISSUE_NUMBER="${DISPATCH_ISSUE_NUMBER}"
echo "number=${{ github.event.inputs.issue_number }}" >> $GITHUB_OUTPUT
elif [ "${{ github.event_name }}" = "push" ]; then
echo "number=70292" >> $GITHUB_OUTPUT
else
ISSUE_NUMBER="${{ github.event.issue.number }}"
echo "number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT
fi
echo "number=$ISSUE_NUMBER" >> $GITHUB_OUTPUT
echo "Issue: https://github.com/${{ github.repository }}/issues/$ISSUE_NUMBER"
env:
DISPATCH_ISSUE_NUMBER: ${{ github.event.inputs.issue_number }}
- uses: actions/checkout@v4
- uses: ./.github/actions/prepare-backend
- uses: ./.github/actions/prepare-frontend
@@ -55,14 +54,11 @@ jobs:
path: repro-bot
- name: Pre-clone metabase bare git repo
run: git clone --bare "https://github.com/${{ github.repository }}.git" repro-bot/git/metabase
run: git clone --bare .git repro-bot/git/metabase
- name: Capture Node.js path for MCP subprocesses
run: echo "NODE_BIN_DIR=$(dirname $(which node))" >> $GITHUB_ENV
- name: Pre-install MCP server dependencies
run: uv sync --directory repro-bot/mcp
- name: Install playwright-cli
run: |
npm install -g @playwright/cli@latest
@@ -103,12 +99,11 @@ jobs:
jq -n \
--arg uv "$UV_PATH" \
--arg key "$LINEAR_API_KEY" \
--arg workspace "${{ github.workspace }}" \
'{
mcpServers: {
"metabase-repro": {
command: $uv,
args: ["run", "--directory", ($workspace + "/repro-bot/mcp"), "--with", "fastmcp", "python", "-m", "metabase_repro"]
args: ["run", "--directory", "mcp", "--with", "fastmcp", "python", "-m", "metabase_repro"]
},
"linear-server": {
url: "https://mcp.linear.app/mcp",
@@ -130,23 +125,18 @@ jobs:
- name: Run repro-bot with Claude Code
id: claude
continue-on-error: true
uses: anthropics/claude-code-action@3ac52d0da9f8ec9ca7b4dc23bb477e36ef9c77a9 # v1
uses: anthropics/claude-code-action@v1
env:
CLAUDE_CODE_DEBUG_LOGS_DIR: /tmp/claude-debug-logs
CLAUDE_WORKING_DIR: ${{ github.workspace }}/repro-bot
MB_PREMIUM_EMBEDDING_TOKEN: ${{ secrets.PR_ENV_MB_PREMIUM_EMBEDDING_TOKEN }}
GITHUB_ACTIONS_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
REPRO_NODE_MODULES_DIR: ${{ github.workspace }}/node_modules
timeout-minutes: 30
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY_REPRO_BOT }}
github_token: ${{ steps.claude-app-token.outputs.token }}
allowed_bots: linear
prompt: |
IMPORTANT: Your working directory is the repo root, but repro-bot lives in the `repro-bot/` subdirectory.
First, run `cd ${{ github.workspace }}/repro-bot` to change into the repro-bot directory before doing anything else.
Then read and follow the instructions in .claude/commands/repro.md to investigate this GitHub issue:
Read and follow the instructions in .claude/commands/repro.md to investigate this GitHub issue:
https://github.com/${{ github.repository }}/issues/${{ steps.issue.outputs.number }}
## CI Environment Notes
@@ -237,7 +227,9 @@ jobs:
mcp__linear-server__get_issue,
mcp__linear-server__list_comments,
mcp__linear-server__list_issues,
mcp__linear-server__save_comment"
mcp__linear-server__list_issue_labels,
mcp__linear-server__save_comment,
mcp__linear-server__save_issue"
--disallowedTools "Bash(git push*),Bash(rm -rf /*)"
- name: Verify repro-bot completed successfully
@@ -267,8 +259,8 @@ jobs:
name: repro-bot-${{ steps.issue.outputs.number }}
if-no-files-found: ignore
path: |
repro-bot/repro/*/SUGGESTIONS.md
repro-bot/repro/*/*.log
repro-bot/repro/*/*.patch
repro-bot/repro/*/playwright/**
repro/*/SUGGESTIONS.md
repro/*/*.log
repro/*/*.patch
repro/*/playwright/**
${{ steps.claude.outputs.execution_file }}

View File

@@ -9,7 +9,7 @@ on:
jobs:
rerun-on-failure:
name: 'Re-run ''${{ github.event.workflow_run.name }}'' workflow'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
# Do not re-run scheduled workflow runs
if: github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.event != 'schedule'
env:

View File

@@ -21,7 +21,7 @@ on:
jobs:
reset-dataset:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 10
env:
CI: 'true'

View File

@@ -1,321 +0,0 @@
name: Auto-resolve backport conflicts
run-name: Auto-resolve conflicts on PR #${{ github.event.pull_request.number || github.event.inputs.pr_number }}
on:
pull_request:
types: [labeled]
workflow_dispatch:
inputs:
pr_number:
description: "PR number of the backport PR with conflicts"
required: true
type: string
max_turns:
description: "Maximum number of Claude turns"
required: false
type: number
default: 75
jobs:
resolve-conflicts:
if: |
(github.event_name == 'pull_request' && github.event.label.name == 'auto-resolve-conflicts') ||
(github.event_name == 'workflow_dispatch')
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 30
permissions:
contents: write
pull-requests: write
id-token: write
env:
GIT_EDITOR: "true"
steps:
- name: Get PR data
id: pr
uses: actions/github-script@v7
with:
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
script: |
let pr;
if (context.eventName === 'workflow_dispatch') {
const { data } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: Number('${{ github.event.inputs.pr_number }}'),
});
pr = data;
} else {
pr = context.payload.pull_request;
}
core.setOutput('number', pr.number);
core.setOutput('head_ref', pr.head.ref);
core.setOutput('base_ref', pr.base.ref);
- name: Checkout PR branch
uses: actions/checkout@v4
with:
ref: ${{ steps.pr.outputs.head_ref }}
fetch-depth: 0
token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
- name: Detect package manager
id: pkg
run: |
if [ -f "bun.lock" ] || [ -f "bun.lockb" ]; then
echo "mgr=bun" >> $GITHUB_OUTPUT
else
echo "mgr=yarn" >> $GITHUB_OUTPUT
fi
- name: Validate backport PR
id: validate
run: |
if [ ! -f "./backport.sh" ]; then
echo "::error::No backport.sh found on this branch. This workflow only works on backport PRs with conflicts."
exit 1
fi
echo "backport.sh found, proceeding with conflict resolution"
cat ./backport.sh
- name: Set up git configuration
run: |
git config --global user.name "Metabase bot"
git config --global user.email "metabase-bot@metabase.com"
git config --global core.editor "true"
- name: Run backport script to create cherry-pick conflicts
id: backport
run: |
bash ./backport.sh 2>&1 || true
# Check if we're in a cherry-pick state with conflicts
CONFLICTED=$(git diff --name-only --diff-filter=U || true)
if [ -n "$CONFLICTED" ]; then
echo "has_conflicts=true" >> $GITHUB_OUTPUT
echo "conflicted_files<<EOF" >> $GITHUB_OUTPUT
echo "$CONFLICTED" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "::notice::Found conflicts in: $CONFLICTED"
else
echo "has_conflicts=false" >> $GITHUB_OUTPUT
echo "::notice::Cherry-pick applied cleanly, no conflicts to resolve"
fi
- name: Push clean cherry-pick (no conflicts)
if: steps.backport.outputs.has_conflicts == 'false'
run: git push --force
- name: Prepare back-end environment
if: steps.backport.outputs.has_conflicts == 'true'
uses: ./.github/actions/prepare-backend
- name: Prepare front-end environment
if: steps.backport.outputs.has_conflicts == 'true'
uses: ./.github/actions/prepare-frontend
- name: Build CLJS for type checking
if: steps.backport.outputs.has_conflicts == 'true'
run: ${{ steps.pkg.outputs.mgr }} run build-pure:cljs
- name: Generate GitHub App Token for Claude
if: steps.backport.outputs.has_conflicts == 'true'
uses: actions/create-github-app-token@v1
id: claude-app-token
with:
app-id: ${{ secrets.METABASE_BOT_APP_ID }}
private-key: ${{ secrets.METABASE_BOT_APP_PRIVATE_KEY }}
- name: Resolve conflicts with Claude
if: steps.backport.outputs.has_conflicts == 'true'
id: claude
uses: anthropics/claude-code-base-action@beta
env:
NODE_VERSION: "22"
with:
# TODO: get a dedicated API key, sharing repro bot's key for now
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY_BACKPORT_FIX }}
model: "claude-sonnet-4-20250514"
max_turns: "${{ github.event.inputs.max_turns || '75' }}"
allowed_tools: "Read,Edit,Write,Bash(git:*),Bash(grep:*),Bash(find:*),Bash(ls:*),Bash(cat:*),Bash(clojure:*),Bash(${{ steps.pkg.outputs.mgr }} run type-check-pure:*),Bash(${{ steps.pkg.outputs.mgr }} run lint-eslint:*),Bash(./bin/mage cljfmt:*),Glob,Grep"
prompt: |
You are resolving git cherry-pick merge conflicts for a Metabase backport PR.
## Context
A commit from the `master` branch is being cherry-picked onto the `${{ steps.pr.outputs.base_ref }}` release branch.
The cherry-pick has failed with conflicts in these files:
${{ steps.backport.outputs.conflicted_files }}
## How to read conflict markers
```
<<<<<<< HEAD
(code from the release branch - the current state)
=======
(code from master - the change being backported)
>>>>>>> <commit-sha>
```
## Common conflict patterns in Metabase backports
- **Module/namespace renames**: A Clojure namespace was renamed or moved between versions. Check what the correct namespace is on the release branch.
- **Test file divergence**: Tests may have been added or reordered differently. Keep the backported test changes while preserving existing release-branch tests.
- **Import path changes**: Frontend imports may reference different paths. Check actual file locations on this branch.
- **Translation files (.po)**: For translation conflicts, prefer the release branch version of existing translations and add new translations from the backported change.
- **Minor context differences**: Surrounding code changed slightly. Adapt the backported change to fit the release branch context.
## Instructions
1. Read each conflicted file to understand the conflict
2. For context, you may search the codebase to understand the current state of the release branch (e.g., check if a module exists at a certain path)
3. Resolve each conflict by editing the file to remove ALL conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) and leave only the correct resolved code
4. The goal is to apply the INTENT of the backported change while adapting it to the release branch's code structure
5. Verify no conflict markers remain by searching for them
6. Auto-format resolved files:
- **Clojure/ClojureScript** (.clj, .cljc, .cljs): run cljfmt to fix formatting:
```
./bin/mage cljfmt-files <file1> <file2> ...
```
- **TypeScript/JavaScript** (.ts, .tsx, .js, .jsx): run eslint with auto-fix:
```
${{ steps.pkg.outputs.mgr }} run lint-eslint --fix
```
7. Validate resolved files before committing:
- **Clojure/ClojureScript** (.clj, .cljc, .cljs): run clj-kondo to verify syntax:
```
clojure -M:kondo --lint <file1> <file2> ...
```
- **TypeScript/JavaScript** (.ts, .tsx, .js, .jsx): run the type checker:
```
${{ steps.pkg.outputs.mgr }} run type-check-pure
```
If either tool reports errors or warnings, fix them before proceeding. CI treats kondo warnings as errors.
Repeat steps 6-7 until all errors are resolved.
7. Once all files are clean, stage and complete the cherry-pick:
```
git add -A
git cherry-pick --continue
```
8. Push the result:
```
git push --force
```
IMPORTANT: Do not skip any conflicted files. Every conflict marker must be resolved.
- name: Check for max turns exceeded
if: always() && steps.claude.outcome != 'skipped'
id: check-failure
run: |
if [ -f "${{ steps.claude.outputs.execution_file }}" ]; then
SUBTYPE=$(jq -r '.[] | select(.type == "result") | .subtype' "${{ steps.claude.outputs.execution_file }}" | tail -1)
if [ "$SUBTYPE" = "error_max_turns" ]; then
echo "max_turns_exceeded=true" >> $GITHUB_OUTPUT
else
echo "max_turns_exceeded=false" >> $GITHUB_OUTPUT
fi
else
echo "max_turns_exceeded=false" >> $GITHUB_OUTPUT
fi
- name: Get commit details
if: always() && steps.claude.outcome == 'success' && steps.check-failure.outputs.max_turns_exceeded != 'true'
id: commit-info
run: |
echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
FILES=$(git diff --name-only HEAD~1)
echo "changed_files<<EOF" >> $GITHUB_OUTPUT
echo "$FILES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Comment on PR (success)
if: always() && steps.claude.outcome == 'success' && steps.check-failure.outputs.max_turns_exceeded != 'true'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
script: |
const sha = '${{ steps.commit-info.outputs.sha }}';
const changedFiles = `${{ steps.commit-info.outputs.changed_files }}`.trim().split('\n').map(f => `- \`${f}\``).join('\n');
await github.rest.issues.createComment({
issue_number: ${{ steps.pr.outputs.number }},
owner: context.repo.owner,
repo: context.repo.repo,
body: [
'🤖 Backport conflicts have been automatically resolved and force-pushed.',
'',
`**Commit:** [\`${sha.substring(0, 10)}\`](https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${sha})`,
'',
'<details>',
'<summary>Changed files</summary>',
'',
changedFiles,
'',
'</details>',
'',
'Please review the changes to make sure the resolution is correct before merging.',
].join('\n')
});
- name: Comment on PR (max turns exceeded)
if: always() && steps.check-failure.outputs.max_turns_exceeded == 'true'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
script: |
await github.rest.issues.createComment({
issue_number: ${{ steps.pr.outputs.number }},
owner: context.repo.owner,
repo: context.repo.repo,
body: [
'🤖 Auto-resolution of backport conflicts stopped because Claude reached the maximum number of turns (${{ github.event.inputs.max_turns || '75' }}).',
'',
'The conflicts may be too complex for automatic resolution, or Claude needed more turns to finish.',
'',
'You can try again with more turns by manually running the [resolve-backport-conflicts workflow](https://github.com/' + context.repo.owner + '/' + context.repo.repo + '/actions/workflows/resolve-backport-conflicts.yml) with a higher `max_turns` value, or resolve the conflicts manually by checking out the branch and running `./backport.sh`.',
].join('\n')
});
- name: Comment on PR (failure)
if: always() && steps.claude.outcome == 'failure' && steps.check-failure.outputs.max_turns_exceeded != 'true'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
script: |
await github.rest.issues.createComment({
issue_number: ${{ steps.pr.outputs.number }},
owner: context.repo.owner,
repo: context.repo.repo,
body: [
'🤖 Auto-resolution of backport conflicts failed.',
'',
'Manual resolution is still required. Check out the branch and run `./backport.sh` to resolve conflicts manually.',
].join('\n')
});
- name: Comment on PR (clean cherry-pick)
if: always() && steps.backport.outputs.has_conflicts == 'false'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
script: |
await github.rest.issues.createComment({
issue_number: ${{ steps.pr.outputs.number }},
owner: context.repo.owner,
repo: context.repo.repo,
body: '🤖 Cherry-pick applied cleanly with no conflicts. Force-pushed the resolved branch.'
});
- name: Remove label
if: always()
uses: actions/github-script@v7
with:
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
script: |
try {
await github.rest.issues.removeLabel({
issue_number: ${{ steps.pr.outputs.number }},
owner: context.repo.owner,
repo: context.repo.repo,
name: 'auto-resolve-conflicts'
});
} catch (e) {
console.log('Label already removed or not found:', e.message);
}

View File

@@ -10,19 +10,11 @@ on:
merge_group:
workflow_dispatch:
permissions:
id-token: write
contents: read
actions: read
checks: write
pull-requests: write
security-events: write
jobs:
files-changed:
if: ${{ !contains(github.event.pull_request.labels.*.name,'ci skip') && !contains(github.event.pull_request.labels.*.name,'minimal-tests') }}
name: Check which files changed
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
outputs:
e2e_all: ${{ steps.changes.outputs.e2e_all }}
@@ -40,7 +32,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
@@ -118,7 +110,7 @@ jobs:
sdk-tests:
needs: [uberjar, embedding-sdk-package, files-changed]
if: always() && !cancelled()
if: always()
uses: ./.github/workflows/embedding-sdk.yml
secrets: inherit
with:

View File

@@ -7,7 +7,7 @@ on:
jobs:
on-issue-opened:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 5
if: github.event.label.name == 'SECURITY'
steps:
@@ -19,7 +19,7 @@ jobs:
core.setOutput('issue_title', ${{ toJson(github.event.issue.title) }}.replaceAll(/"/g, '\\"'));
- name: Send the issue ${{ github.event.issue.number }} to Slack
id: slack
uses: slackapi/slack-github-action@70cd7be8e40a46e8b0eced40b0de447bdb42f68e # v1.26.0
uses: slackapi/slack-github-action@v1.26.0
with:
payload: |
{

View File

@@ -14,7 +14,7 @@ concurrency:
jobs:
semantic-search-tests-h2:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 40
strategy:
fail-fast: false
@@ -61,14 +61,15 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
semantic-search-tests-mariadb:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 40
strategy:
fail-fast: false
@@ -76,11 +77,11 @@ jobs:
version:
- name: MariaDB 10.6 with pgvector pg17
junit-name: semantic-search-tests-mariadb-10-6
mariadb-image: metabase/mariadb:10.6 # https://github.com/metabase/metabase-mariadb-docker-image
mariadb-image: circleci/mariadb:10.6
pgvector-image: pgvector/pgvector:pg17
- name: MariaDB Latest with pgvector pg17
junit-name: semantic-search-tests-mariadb-latest
mariadb-image: mariadb:latest
mariadb-image: circleci/mariadb:latest
pgvector-image: pgvector/pgvector:pg17
job:
- name: Semantic Search Tests
@@ -103,15 +104,15 @@ jobs:
ports:
- "3306:3306"
env:
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: true
MARIADB_DATABASE: mb_test
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: circle_test
env:
CI: 'true'
DRIVERS: mysql
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
MB_PGVECTOR_DB_URL: 'jdbc:postgres://localhost:5432/mb_semantic_search?user=postgres&password=postgres'
@@ -134,14 +135,15 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
semantic-search-tests-mysql:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 40
strategy:
fail-fast: false
@@ -149,7 +151,7 @@ jobs:
version:
- name: MySQL 8.4 with pgvector pg17
junit-name: semantic-search-tests-mysql-8-4
mysql-image: mysql:8.4
mysql-image: cimg/mysql:8.4
pgvector-image: pgvector/pgvector:pg17
- name: MySQL Latest with pgvector pg17
junit-name: semantic-search-tests-mysql-latest
@@ -177,14 +179,14 @@ jobs:
- "3306:3306"
env:
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: mb_test
MYSQL_DATABASE: circle_test
env:
CI: 'true'
DRIVERS: mysql
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: mb_test
MB_DB_DBNAME: circle_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
MB_PGVECTOR_DB_URL: 'jdbc:postgres://localhost:5432/mb_semantic_search?user=postgres&password=postgres'
@@ -207,14 +209,15 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
semantic-search-tests-postgres:
if: ${{ !inputs.skip }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 40
strategy:
fail-fast: false
@@ -281,7 +284,8 @@ jobs:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
role-to-assume: ${{ secrets.CI_TEST_RESULTS_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
@@ -292,7 +296,7 @@ jobs:
- semantic-search-tests-mariadb
- semantic-search-tests-mysql
- semantic-search-tests-postgres
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 5
name: semantic-search-tests-result
if: always() && !cancelled()

View File

@@ -1,39 +0,0 @@
name: Serialization
on:
push:
branches:
- 'master'
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
cancel-in-progress: true
jobs:
files-changed:
name: Check which files changed
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 3
outputs:
serialization_baseline: ${{ steps.changes.outputs.serialization_baseline }}
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
filters: .github/file-paths.yaml
validate-serialization-baseline:
needs: files-changed
if: needs.files-changed.outputs.serialization_baseline == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Validate serialization baseline schema
run: bunx @metabase/representations validate-schema --folder test_resources/serialization_baseline

View File

@@ -9,13 +9,9 @@ on:
type: string
required: true
permissions:
id-token: write
contents: read
jobs:
set-announce-url:
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- name: Validate input
@@ -25,9 +21,10 @@ jobs:
exit 1
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.CI_RELEASE_IAM_ROLE }}
aws-access-key-id: ${{ secrets.AWS_S3_RELEASE_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_S3_RELEASE_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
- name: Update announcement url
uses: actions/github-script@v7

View File

@@ -8,14 +8,14 @@ on:
jobs:
files-changed:
name: Check which files changed
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
snowplow: ${{ steps.changes.outputs.snowplow }}
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@0bc4621a3135347011ad047f9ecf449bf72ce2bd # v3.0.0
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
@@ -24,7 +24,7 @@ jobs:
lint:
needs: files-changed
if: needs.files-changed.outputs.snowplow == 'true'
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4

View File

@@ -18,7 +18,7 @@ jobs:
generate-poms:
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
name: Generate pom.xml files
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Prepare back-end environment
@@ -37,7 +37,7 @@ jobs:
frontend-projects:
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
name: ${{ matrix.project.name }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
strategy:
matrix:
project:
@@ -51,7 +51,7 @@ jobs:
category: release-helper
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ secrets.GITHUB_TOKEN }}
@@ -71,7 +71,7 @@ jobs:
bun install --yarn
sed -i -E 's/< ([0-9]+)\.0\.0"/< \1"/g; s/< ([0-9]+)\.0"/< \1"/g' yarn.lock || true
working-directory: release
- uses: snyk/actions/setup@b98d498629f1c368650224d6d212bf7dfa89e4bf # 0.4.0
- uses: snyk/actions/setup@0.4.0
- name: Run snyk test
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
@@ -88,7 +88,7 @@ jobs:
needs: generate-poms
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
name: ${{ matrix.project.name }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-22.04
strategy:
matrix:
project:
@@ -148,7 +148,7 @@ jobs:
category: driver-vertica
steps:
- uses: actions/checkout@v4
- uses: snyk/actions/setup@b98d498629f1c368650224d6d212bf7dfa89e4bf # 0.4.0
- uses: snyk/actions/setup@0.4.0
- name: Download pom files
uses: actions/download-artifact@v4
with:

View File

@@ -12,7 +12,7 @@ jobs:
close-stale-prs:
# don't run this workflow on a cron for forks
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ${{ vars.DEFAULT_RUNNER_KEY }}
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/stale@v9

Some files were not shown because too many files have changed in this diff Show More