Signed-off-by: Max <ai-agent@topdoglabs.com>
This commit is contained in:
parent
7259d24b89
commit
60aed51f3c
69
supabase/nightly_sprint_rollover.sql
Normal file
69
supabase/nightly_sprint_rollover.sql
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
-- 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;
|
||||||
|
$$;
|
||||||
|
|
||||||
@ -241,3 +241,75 @@ 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