Compare commits
No commits in common. "60aed51f3cfb5ec9928a38e37c26c765203cb162" and "7d66c998150812664776046f2e5bbfbce72eafe2" have entirely different histories.
60aed51f3c
...
7d66c99815
@ -5,9 +5,6 @@ Complete command-line interface for the Gantt Board. All web UI operations avail
|
|||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Pull latest schema from Supabase into supabase/schema.sql
|
|
||||||
SUPABASE_DB_URL='postgresql://...' ./scripts/pull-supabase-schema.sh
|
|
||||||
|
|
||||||
# List all tasks
|
# List all tasks
|
||||||
./scripts/gantt.sh task list
|
./scripts/gantt.sh task list
|
||||||
|
|
||||||
@ -27,24 +24,6 @@ SUPABASE_DB_URL='postgresql://...' ./scripts/pull-supabase-schema.sh
|
|||||||
./scripts/gantt.sh task attach <task-id> ./notes.md
|
./scripts/gantt.sh task attach <task-id> ./notes.md
|
||||||
```
|
```
|
||||||
|
|
||||||
## Schema Dump Script
|
|
||||||
|
|
||||||
Use `pull-supabase-schema.sh` when `supabase/schema.sql` needs to match the live database:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
SUPABASE_DB_URL='postgresql://postgres:***@db.<project-ref>.supabase.co:5432/postgres?sslmode=require' \
|
|
||||||
./scripts/pull-supabase-schema.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Optional:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Include additional schemas
|
|
||||||
SCHEMAS='public,auth,storage' \
|
|
||||||
SUPABASE_DB_URL='postgresql://...' \
|
|
||||||
./scripts/pull-supabase-schema.sh supabase/full-schema.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
## Main CLI: `gantt.sh`
|
## Main CLI: `gantt.sh`
|
||||||
|
|
||||||
A unified CLI that covers all API operations.
|
A unified CLI that covers all API operations.
|
||||||
|
|||||||
@ -1,95 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat <<'EOF'
|
|
||||||
Usage:
|
|
||||||
SUPABASE_DB_URL='postgresql://...' ./scripts/pull-supabase-schema.sh [output_file]
|
|
||||||
|
|
||||||
Description:
|
|
||||||
Dumps the current Supabase schema using pg_dump and writes it to a file.
|
|
||||||
|
|
||||||
Defaults:
|
|
||||||
output_file: supabase/schema.sql
|
|
||||||
SCHEMAS: public
|
|
||||||
|
|
||||||
Optional env vars:
|
|
||||||
SCHEMAS Comma-separated schemas to include (example: public,auth,storage)
|
|
||||||
SUPABASE_DB_URL Postgres connection URI from Supabase Database settings
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
SUPABASE_DB_URL='postgresql://postgres:***@db.xxx.supabase.co:5432/postgres?sslmode=require' \
|
|
||||||
./scripts/pull-supabase-schema.sh
|
|
||||||
|
|
||||||
SCHEMAS='public,auth,storage' \
|
|
||||||
SUPABASE_DB_URL='postgresql://postgres:***@db.xxx.supabase.co:5432/postgres?sslmode=require' \
|
|
||||||
./scripts/pull-supabase-schema.sh supabase/full-schema.sql
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
||||||
usage
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command -v pg_dump >/dev/null 2>&1; then
|
|
||||||
echo "Error: pg_dump is required but was not found."
|
|
||||||
echo "Install PostgreSQL client tools (e.g. 'brew install postgresql@16')."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "${SUPABASE_DB_URL:-}" ]]; then
|
|
||||||
echo "Error: SUPABASE_DB_URL is not set."
|
|
||||||
echo "Copy the Postgres connection string from Supabase:"
|
|
||||||
echo " Project Settings -> Database -> Connection string (URI)"
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
OUTPUT_FILE="${1:-supabase/schema.sql}"
|
|
||||||
SCHEMAS_CSV="${SCHEMAS:-public}"
|
|
||||||
DB_URL="${SUPABASE_DB_URL}"
|
|
||||||
|
|
||||||
# Ensure SSL is required if it is not already present in the URI.
|
|
||||||
if [[ "${DB_URL}" != *"sslmode="* ]]; then
|
|
||||||
if [[ "${DB_URL}" == *"?"* ]]; then
|
|
||||||
DB_URL="${DB_URL}&sslmode=require"
|
|
||||||
else
|
|
||||||
DB_URL="${DB_URL}?sslmode=require"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
IFS=',' read -r -a RAW_SCHEMAS <<< "${SCHEMAS_CSV}"
|
|
||||||
SCHEMA_ARGS=()
|
|
||||||
for raw_schema in "${RAW_SCHEMAS[@]}"; do
|
|
||||||
schema="$(printf "%s" "${raw_schema}" | tr -d '[:space:]')"
|
|
||||||
if [[ -n "${schema}" ]]; then
|
|
||||||
SCHEMA_ARGS+=(--schema="${schema}")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ ${#SCHEMA_ARGS[@]} -eq 0 ]]; then
|
|
||||||
echo "Error: no schemas selected. Set SCHEMAS to at least one schema name."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p "$(dirname "${OUTPUT_FILE}")"
|
|
||||||
tmp_file="$(mktemp)"
|
|
||||||
trap 'rm -f "${tmp_file}"' EXIT
|
|
||||||
|
|
||||||
pg_dump "${DB_URL}" \
|
|
||||||
--schema-only \
|
|
||||||
--no-owner \
|
|
||||||
--no-privileges \
|
|
||||||
"${SCHEMA_ARGS[@]}" \
|
|
||||||
> "${tmp_file}"
|
|
||||||
|
|
||||||
{
|
|
||||||
echo "-- Generated by scripts/pull-supabase-schema.sh"
|
|
||||||
echo "-- Generated at: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
||||||
echo "-- Schemas: ${SCHEMAS_CSV}"
|
|
||||||
echo
|
|
||||||
cat "${tmp_file}"
|
|
||||||
} > "${OUTPUT_FILE}"
|
|
||||||
|
|
||||||
echo "Schema dump written to ${OUTPUT_FILE}"
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
-- Nightly sprint auto-close + rollover job
|
|
||||||
-- Schedule: 12:01 AM UTC every day
|
|
||||||
|
|
||||||
CREATE EXTENSION IF NOT EXISTS pg_cron;
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION public.complete_ended_sprints_and_rollover()
|
|
||||||
RETURNS void
|
|
||||||
LANGUAGE plpgsql
|
|
||||||
SECURITY DEFINER
|
|
||||||
SET search_path = public
|
|
||||||
AS $$
|
|
||||||
DECLARE
|
|
||||||
ended_sprint RECORD;
|
|
||||||
next_sprint_id UUID;
|
|
||||||
BEGIN
|
|
||||||
FOR ended_sprint IN
|
|
||||||
SELECT id, project_id
|
|
||||||
FROM public.sprints
|
|
||||||
WHERE status <> 'completed'
|
|
||||||
AND end_date < CURRENT_DATE
|
|
||||||
ORDER BY end_date ASC, start_date ASC
|
|
||||||
LOOP
|
|
||||||
-- Pick the next non-completed sprint in the same project.
|
|
||||||
SELECT s.id
|
|
||||||
INTO next_sprint_id
|
|
||||||
FROM public.sprints s
|
|
||||||
WHERE s.project_id = ended_sprint.project_id
|
|
||||||
AND s.status <> 'completed'
|
|
||||||
AND s.id <> ended_sprint.id
|
|
||||||
ORDER BY s.start_date ASC
|
|
||||||
LIMIT 1;
|
|
||||||
|
|
||||||
IF next_sprint_id IS NOT NULL THEN
|
|
||||||
UPDATE public.tasks
|
|
||||||
SET sprint_id = next_sprint_id
|
|
||||||
WHERE sprint_id = ended_sprint.id
|
|
||||||
AND status NOT IN ('done', 'canceled', 'archived');
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
UPDATE public.sprints
|
|
||||||
SET status = 'completed'
|
|
||||||
WHERE id = ended_sprint.id;
|
|
||||||
END LOOP;
|
|
||||||
END;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
DO $$
|
|
||||||
DECLARE
|
|
||||||
existing_job_id BIGINT;
|
|
||||||
BEGIN
|
|
||||||
-- Keep this idempotent: replace existing job if present.
|
|
||||||
SELECT jobid
|
|
||||||
INTO existing_job_id
|
|
||||||
FROM cron.job
|
|
||||||
WHERE jobname = 'nightly-sprint-rollover-0001'
|
|
||||||
LIMIT 1;
|
|
||||||
|
|
||||||
IF existing_job_id IS NOT NULL THEN
|
|
||||||
PERFORM cron.unschedule(existing_job_id);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
PERFORM cron.schedule(
|
|
||||||
'nightly-sprint-rollover-0001',
|
|
||||||
'1 0 * * *',
|
|
||||||
'select public.complete_ended_sprints_and_rollover();'
|
|
||||||
);
|
|
||||||
END;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
@ -9,17 +9,14 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
|||||||
-- ============================================
|
-- ============================================
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
legacy_id TEXT UNIQUE, -- For migration from SQLite
|
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
email TEXT NOT NULL UNIQUE,
|
email TEXT NOT NULL UNIQUE,
|
||||||
avatar_url TEXT,
|
avatar_url TEXT,
|
||||||
password_hash TEXT NOT NULL,
|
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Create index on email for faster lookups
|
-- Create index on email for faster lookups
|
||||||
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
||||||
CREATE INDEX IF NOT EXISTS idx_users_legacy_id ON users(legacy_id);
|
|
||||||
|
|
||||||
-- Enable RLS
|
-- Enable RLS
|
||||||
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
|
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
|
||||||
@ -32,6 +29,17 @@ CREATE POLICY "Users can read own data" ON users
|
|||||||
CREATE POLICY "Users can update own data" ON users
|
CREATE POLICY "Users can update own data" ON users
|
||||||
FOR UPDATE USING (auth.uid() = id);
|
FOR UPDATE USING (auth.uid() = id);
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- PROFILES TABLE
|
||||||
|
-- ============================================
|
||||||
|
CREATE TABLE IF NOT EXISTS profiles (
|
||||||
|
id UUID PRIMARY KEY REFERENCES auth.users(id),
|
||||||
|
name TEXT,
|
||||||
|
avatar_url TEXT,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
-- ============================================
|
-- ============================================
|
||||||
-- SESSIONS TABLE
|
-- SESSIONS TABLE
|
||||||
-- ============================================
|
-- ============================================
|
||||||
@ -83,16 +91,12 @@ CREATE POLICY "Service role manages reset tokens" ON password_reset_tokens
|
|||||||
-- ============================================
|
-- ============================================
|
||||||
CREATE TABLE IF NOT EXISTS projects (
|
CREATE TABLE IF NOT EXISTS projects (
|
||||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
legacy_id TEXT UNIQUE, -- For migration from SQLite
|
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
color TEXT NOT NULL,
|
color TEXT NOT NULL,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Create index for legacy ID lookups
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_projects_legacy_id ON projects(legacy_id);
|
|
||||||
|
|
||||||
-- Enable RLS
|
-- Enable RLS
|
||||||
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
|
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
@ -117,7 +121,6 @@ CREATE POLICY "Authenticated users can delete projects" ON projects
|
|||||||
-- ============================================
|
-- ============================================
|
||||||
CREATE TABLE IF NOT EXISTS sprints (
|
CREATE TABLE IF NOT EXISTS sprints (
|
||||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
legacy_id TEXT UNIQUE, -- For migration from SQLite
|
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
goal TEXT,
|
goal TEXT,
|
||||||
start_date DATE NOT NULL,
|
start_date DATE NOT NULL,
|
||||||
@ -129,7 +132,6 @@ CREATE TABLE IF NOT EXISTS sprints (
|
|||||||
|
|
||||||
-- Create indexes
|
-- Create indexes
|
||||||
CREATE INDEX IF NOT EXISTS idx_sprints_project_id ON sprints(project_id);
|
CREATE INDEX IF NOT EXISTS idx_sprints_project_id ON sprints(project_id);
|
||||||
CREATE INDEX IF NOT EXISTS idx_sprints_legacy_id ON sprints(legacy_id);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_sprints_dates ON sprints(start_date, end_date);
|
CREATE INDEX IF NOT EXISTS idx_sprints_dates ON sprints(start_date, end_date);
|
||||||
|
|
||||||
-- Enable RLS
|
-- Enable RLS
|
||||||
@ -144,7 +146,6 @@ CREATE POLICY "Authenticated users can manage sprints" ON sprints
|
|||||||
-- ============================================
|
-- ============================================
|
||||||
CREATE TABLE IF NOT EXISTS tasks (
|
CREATE TABLE IF NOT EXISTS tasks (
|
||||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
legacy_id TEXT UNIQUE, -- For migration from SQLite
|
|
||||||
title TEXT NOT NULL,
|
title TEXT NOT NULL,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
type TEXT NOT NULL CHECK (type IN ('idea', 'task', 'bug', 'research', 'plan')),
|
type TEXT NOT NULL CHECK (type IN ('idea', 'task', 'bug', 'research', 'plan')),
|
||||||
@ -155,15 +156,8 @@ CREATE TABLE IF NOT EXISTS tasks (
|
|||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
created_by_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
created_by_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||||
created_by_name TEXT,
|
|
||||||
created_by_avatar_url TEXT,
|
|
||||||
updated_by_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
updated_by_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||||
updated_by_name TEXT,
|
|
||||||
updated_by_avatar_url TEXT,
|
|
||||||
assignee_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
assignee_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||||
assignee_name TEXT,
|
|
||||||
assignee_email TEXT,
|
|
||||||
assignee_avatar_url TEXT,
|
|
||||||
due_date DATE,
|
due_date DATE,
|
||||||
comments JSONB NOT NULL DEFAULT '[]'::jsonb,
|
comments JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||||
tags JSONB NOT NULL DEFAULT '[]'::jsonb,
|
tags JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||||
@ -177,7 +171,6 @@ CREATE INDEX IF NOT EXISTS idx_tasks_assignee_id ON tasks(assignee_id);
|
|||||||
CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
|
CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
|
||||||
CREATE INDEX IF NOT EXISTS idx_tasks_priority ON tasks(priority);
|
CREATE INDEX IF NOT EXISTS idx_tasks_priority ON tasks(priority);
|
||||||
CREATE INDEX IF NOT EXISTS idx_tasks_due_date ON tasks(due_date);
|
CREATE INDEX IF NOT EXISTS idx_tasks_due_date ON tasks(due_date);
|
||||||
CREATE INDEX IF NOT EXISTS idx_tasks_legacy_id ON tasks(legacy_id);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_tasks_updated_at ON tasks(updated_at DESC);
|
CREATE INDEX IF NOT EXISTS idx_tasks_updated_at ON tasks(updated_at DESC);
|
||||||
|
|
||||||
-- Create trigger to auto-update updated_at
|
-- Create trigger to auto-update updated_at
|
||||||
@ -202,26 +195,6 @@ ALTER TABLE tasks ENABLE ROW LEVEL SECURITY;
|
|||||||
CREATE POLICY "Authenticated users can manage tasks" ON tasks
|
CREATE POLICY "Authenticated users can manage tasks" ON tasks
|
||||||
FOR ALL USING (auth.role() = 'authenticated');
|
FOR ALL USING (auth.role() = 'authenticated');
|
||||||
|
|
||||||
-- ============================================
|
|
||||||
-- META TABLE (for app state like lastUpdated)
|
|
||||||
-- ============================================
|
|
||||||
CREATE TABLE IF NOT EXISTS meta (
|
|
||||||
key TEXT PRIMARY KEY,
|
|
||||||
value TEXT NOT NULL,
|
|
||||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Enable RLS
|
|
||||||
ALTER TABLE meta ENABLE ROW LEVEL SECURITY;
|
|
||||||
|
|
||||||
-- Policy: All authenticated users can manage meta
|
|
||||||
CREATE POLICY "Authenticated users can manage meta" ON meta
|
|
||||||
FOR ALL USING (auth.role() = 'authenticated');
|
|
||||||
|
|
||||||
-- Insert initial lastUpdated value
|
|
||||||
INSERT INTO meta (key, value) VALUES ('lastUpdated', extract(epoch from now()) * 1000)
|
|
||||||
ON CONFLICT (key) DO UPDATE SET value = excluded.value;
|
|
||||||
|
|
||||||
-- ============================================
|
-- ============================================
|
||||||
-- FUNCTIONS
|
-- FUNCTIONS
|
||||||
-- ============================================
|
-- ============================================
|
||||||
@ -241,75 +214,3 @@ BEGIN
|
|||||||
DELETE FROM password_reset_tokens WHERE expires_at <= NOW() OR used = true;
|
DELETE FROM password_reset_tokens WHERE expires_at <= NOW() OR used = true;
|
||||||
END;
|
END;
|
||||||
$$ LANGUAGE plpgsql;
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
-- ============================================
|
|
||||||
-- NIGHTLY SPRINT AUTO-CLOSE + ROLLOVER
|
|
||||||
-- ============================================
|
|
||||||
-- Runs every night at 12:01 AM UTC.
|
|
||||||
-- If you need local time, convert your desired local time to UTC in the cron expression.
|
|
||||||
|
|
||||||
CREATE EXTENSION IF NOT EXISTS pg_cron;
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION public.complete_ended_sprints_and_rollover()
|
|
||||||
RETURNS void
|
|
||||||
LANGUAGE plpgsql
|
|
||||||
SECURITY DEFINER
|
|
||||||
SET search_path = public
|
|
||||||
AS $$
|
|
||||||
DECLARE
|
|
||||||
ended_sprint RECORD;
|
|
||||||
next_sprint_id UUID;
|
|
||||||
BEGIN
|
|
||||||
FOR ended_sprint IN
|
|
||||||
SELECT id, project_id
|
|
||||||
FROM public.sprints
|
|
||||||
WHERE status <> 'completed'
|
|
||||||
AND end_date < CURRENT_DATE
|
|
||||||
ORDER BY end_date ASC, start_date ASC
|
|
||||||
LOOP
|
|
||||||
-- Pick the next non-completed sprint in the same project.
|
|
||||||
SELECT s.id
|
|
||||||
INTO next_sprint_id
|
|
||||||
FROM public.sprints s
|
|
||||||
WHERE s.project_id = ended_sprint.project_id
|
|
||||||
AND s.status <> 'completed'
|
|
||||||
AND s.id <> ended_sprint.id
|
|
||||||
ORDER BY s.start_date ASC
|
|
||||||
LIMIT 1;
|
|
||||||
|
|
||||||
IF next_sprint_id IS NOT NULL THEN
|
|
||||||
UPDATE public.tasks
|
|
||||||
SET sprint_id = next_sprint_id
|
|
||||||
WHERE sprint_id = ended_sprint.id
|
|
||||||
AND status NOT IN ('done', 'canceled', 'archived');
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
UPDATE public.sprints
|
|
||||||
SET status = 'completed'
|
|
||||||
WHERE id = ended_sprint.id;
|
|
||||||
END LOOP;
|
|
||||||
END;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
DO $$
|
|
||||||
DECLARE
|
|
||||||
existing_job_id BIGINT;
|
|
||||||
BEGIN
|
|
||||||
-- Keep this idempotent: replace existing job if present.
|
|
||||||
SELECT jobid
|
|
||||||
INTO existing_job_id
|
|
||||||
FROM cron.job
|
|
||||||
WHERE jobname = 'nightly-sprint-rollover-0001'
|
|
||||||
LIMIT 1;
|
|
||||||
|
|
||||||
IF existing_job_id IS NOT NULL THEN
|
|
||||||
PERFORM cron.unschedule(existing_job_id);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
PERFORM cron.schedule(
|
|
||||||
'nightly-sprint-rollover-0001',
|
|
||||||
'1 0 * * *',
|
|
||||||
'select public.complete_ended_sprints_and_rollover();'
|
|
||||||
);
|
|
||||||
END;
|
|
||||||
$$;
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user