From bd9c52dbd0f4d5bc933aa571f2edf8721de7a451 Mon Sep 17 00:00:00 2001
From: Cole Helbling <cole.e.helbling@outlook.com>
Date: Wed, 5 May 2021 14:03:51 -0700
Subject: [PATCH 1/3] Project: delete the `.jobsets` jobset if project is no
 longer declarative

"No longer declarative" as defined by the "Edit project" page is an empty spec
file.
---
 src/lib/Hydra/Controller/Project.pm | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/lib/Hydra/Controller/Project.pm b/src/lib/Hydra/Controller/Project.pm
index e6a2dba8..20b3bd3b 100644
--- a/src/lib/Hydra/Controller/Project.pm
+++ b/src/lib/Hydra/Controller/Project.pm
@@ -169,6 +169,8 @@ sub updateProject {
             , emailoverride => ""
             , triggertime => time
             });
+    } else {
+        $project->jobsets->search({ name => ".jobsets" })->delete;
     }
 }
 

From 6107040bf5c29872c18fed624ce1a8c8489e750e Mon Sep 17 00:00:00 2001
From: Cole Helbling <cole.e.helbling@outlook.com>
Date: Wed, 5 May 2021 14:42:19 -0700
Subject: [PATCH 2/3] Project: clear `decltype` and `declvalue` when project is
 no longer declarative

---
 src/lib/Hydra/Controller/Project.pm | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/lib/Hydra/Controller/Project.pm b/src/lib/Hydra/Controller/Project.pm
index 20b3bd3b..c38ff6ad 100644
--- a/src/lib/Hydra/Controller/Project.pm
+++ b/src/lib/Hydra/Controller/Project.pm
@@ -171,6 +171,10 @@ sub updateProject {
             });
     } else {
         $project->jobsets->search({ name => ".jobsets" })->delete;
+        $project->update(
+            { decltype => ""
+            , declvalue => ""
+            });
     }
 }
 

From 588a3a774f8b2d8fca74d3d3acc582353945ad41 Mon Sep 17 00:00:00 2001
From: Cole Helbling <cole.e.helbling@outlook.com>
Date: Wed, 5 May 2021 14:42:53 -0700
Subject: [PATCH 3/3] Project: add test for declarative->normal project
 transition

Also split into subtests.
---
 t/Controller/projects.t | 146 ++++++++++++++++++++++++++++++++++------
 1 file changed, 126 insertions(+), 20 deletions(-)

diff --git a/t/Controller/projects.t b/t/Controller/projects.t
index 71a37ab4..af3db3d8 100644
--- a/t/Controller/projects.t
+++ b/t/Controller/projects.t
@@ -1,7 +1,7 @@
 use feature 'unicode_strings';
 use strict;
 use Setup;
-use JSON qw(decode_json);
+use JSON qw(decode_json encode_json);
 
 my %ctx = test_init();
 
@@ -17,27 +17,133 @@ Catalyst::Test->import('Hydra');
 my $db = Hydra::Model::DB->new;
 hydra_setup($db);
 
-my $project = $db->resultset('Projects')->create({name => "tests", displayname => "", owner => "root"});
+# Create a user to log in to
+my $user = $db->resultset('Users')->create({ username => 'alice', emailaddress => 'root@invalid.org', password => '!' });
+$user->setPassword('foobar');
+$user->userroles->update_or_create({ role => 'admin' });
 
-my $projectinfo = request(GET '/project/tests',
-    Accept => 'application/json',
-);
+my $project = $db->resultset('Projects')->create({name => "tests", displayname => "Tests", owner => "root"});
 
-ok($projectinfo->is_success);
-is(decode_json($projectinfo->content), {
-    description => "",
-    displayname => "",
-    enabled => JSON::true,
-    hidden => JSON::false,
-    homepage => "",
-    jobsets => [],
-    name => "tests",
-    owner => "root",
-    declarative => {
-        file => "",
-        type => "",
-        value => ""
+# Login and save cookie for future requests
+my $req = request(POST '/login',
+    Referer => 'http://localhost/',
+    Content => {
+        username => 'alice',
+        password => 'foobar'
     }
-});
+);
+is($req->code, 302);
+my $cookie = $req->header("set-cookie");
+
+subtest "Read project 'tests'" => sub {
+    my $projectinfo = request(GET '/project/tests',
+        Accept => 'application/json',
+    );
+
+    ok($projectinfo->is_success);
+    is(decode_json($projectinfo->content), {
+        description => "",
+        displayname => "Tests",
+        enabled => JSON::true,
+        hidden => JSON::false,
+        homepage => "",
+        jobsets => [],
+        name => "tests",
+        owner => "root",
+        declarative => {
+            file => "",
+            type => "",
+            value => ""
+        }
+    });
+};
+
+subtest "Transitioning from declarative project to normal" => sub {
+    subtest "Make project declarative" => sub {
+        my $projectupdate = request(PUT '/project/tests',
+            Accept => 'application/json',
+            Content_Type => 'application/json',
+            Cookie => $cookie,
+            Content => encode_json({
+                enabled => JSON::true,
+                visible => JSON::true,
+                name => "tests",
+                displayname => "Tests",
+                declarative => {
+                    file => "bogus",
+                    type => "boolean",
+                    value => "false"
+                }
+            })
+        );
+        ok($projectupdate->is_success);
+    };
+
+    subtest "Project has '.jobsets' jobset" => sub {
+        my $projectinfo = request(GET '/project/tests',
+            Accept => 'application/json',
+        );
+
+        ok($projectinfo->is_success);
+        is(decode_json($projectinfo->content), {
+            description => "",
+            displayname => "Tests",
+            enabled => JSON::true,
+            hidden => JSON::false,
+            homepage => "",
+            jobsets => [".jobsets"],
+            name => "tests",
+            owner => "root",
+            declarative => {
+                file => "bogus",
+                type => "boolean",
+                value => "false"
+            }
+        });
+    };
+
+    subtest "Make project normal" => sub {
+        my $projectupdate = request(PUT '/project/tests',
+            Accept => 'application/json',
+            Content_Type => 'application/json',
+            Cookie => $cookie,
+            Content => encode_json({
+                enabled => JSON::true,
+                visible => JSON::true,
+                name => "tests",
+                displayname => "Tests",
+                declarative => {
+                    file => "",
+                    type => "boolean",
+                    value => "false"
+                }
+            })
+        );
+        ok($projectupdate->is_success);
+    };
+
+    subtest "Project doesn't have '.jobsets' jobset" => sub {
+        my $projectinfo = request(GET '/project/tests',
+            Accept => 'application/json',
+        );
+
+        ok($projectinfo->is_success);
+        is(decode_json($projectinfo->content), {
+            description => "",
+            displayname => "Tests",
+            enabled => JSON::true,
+            hidden => JSON::false,
+            homepage => "",
+            jobsets => [],
+            name => "tests",
+            owner => "root",
+            declarative => {
+                file => "",
+                type => "",
+                value => ""
+            }
+        });
+    };
+};
 
 done_testing;