Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions lib/code_corps/model/task_list.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ defmodule CodeCorps.TaskList do
@type t :: %__MODULE__{}

schema "task_lists" do
field :done, :boolean, default: false
field :inbox, :boolean, default: false
field :name, :string
field :order, :integer
field :position, :integer, virtual: true
field :pull_requests, :boolean, default: false

belongs_to :project, CodeCorps.Project
has_many :tasks, CodeCorps.Task
Expand All @@ -29,11 +31,11 @@ defmodule CodeCorps.TaskList do
name: "Backlog",
position: 2
}, %{
inbox: false,
pull_requests: true,
name: "In Progress",
position: 3
}, %{
inbox: false,
done: true,
name: "Done",
position: 4
}
Expand All @@ -52,8 +54,11 @@ defmodule CodeCorps.TaskList do

def create_changeset(struct, params) do
struct
|> cast(params, [:inbox])
|> cast(params, [:done, :inbox, :pull_requests])
|> changeset(params)
|> validate_required([:inbox])
|> validate_required([:done, :inbox, :pull_requests])
|> unique_constraint(:done, name: "task_lists_project_id_done_index")
|> unique_constraint(:inbox, name: "task_lists_project_id_inbox_index")
|> unique_constraint(:pull_requests, name: "task_lists_project_id_pull_requests_index")
end
end
2 changes: 1 addition & 1 deletion lib/code_corps_web/views/task_list_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule CodeCorpsWeb.TaskListView do
use CodeCorpsWeb, :view
use JaSerializer.PhoenixView

attributes [:inbox, :name, :order, :inserted_at, :updated_at]
attributes [:done, :inbox, :name, :order, :pull_requests, :inserted_at, :updated_at]

has_one :project, type: "project", field: :project_id

Expand Down
37 changes: 37 additions & 0 deletions priv/repo/migrations/20171106045740_add_done_to_task_list.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
defmodule CodeCorps.Repo.Migrations.AddDoneToTaskList do
use Ecto.Migration

import Ecto.Query

alias CodeCorps.Repo

def up do
alter table(:task_lists) do
add :done, :boolean, default: false
end

flush()

from(tl in "task_lists", where: [name: "Done"], update: [set: [done: true]])
|> Repo.update_all([])

task_list_query =
from(tl in "task_lists", where: [done: true], select: [:id])

# tests do not have any data, so we need to account for potential nil
case task_list_query |> Repo.one do
%{id: done_list_id} ->
task_update_query = from t in "tasks",
where: [status: "closed"],
update: [set: [task_list_id: ^done_list_id]]
task_update_query |> Repo.update_all([])
nil -> nil
end
end

def down do
alter table(:task_lists) do
remove :done
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
defmodule CodeCorps.Repo.Migrations.AddPullRequestsToTaskList do
use Ecto.Migration

import Ecto.Query

alias CodeCorps.Repo

def up do
alter table(:task_lists) do
add :pull_requests, :boolean, default: false
end

flush()

# set all "In Progress" task lists to now contain pull requests
from(
tl in "task_lists",
where: [name: "In Progress"],
update: [set: [pull_requests: true]]
) |> Repo.update_all([])

# get projects paired with associated pull request task list as ids
task_parent_data = from(
p in "projects",
left_join:
tl in "task_lists",
on: tl.project_id == p.id,
where: tl.pull_requests == true,
select: {p.id, tl.id}
) |> Repo.all

# get all tasks for projects, associated to github pull requests and
# assign them to the pull request task list
task_parent_data |> Enum.each(fn {project_id, pr_list_id} ->
from(
t in "tasks",
where: [project_id: ^project_id],
where: t.status != "closed",
where: not is_nil(t.github_issue_id),
inner_join:
gi in "github_issues",
on: t.github_issue_id == gi.id,
where: not is_nil(gi.github_pull_request_id),
update: [set: [task_list_id: ^pr_list_id]]
) |> Repo.update_all([])
end)
Copy link
Copy Markdown
Contributor

@begedin begedin Nov 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joshsmith I really feel this is the way to go with migrations.

If our schema modules do not match the schemas in any migration step, the code will fail, but if we go like this, "schemaless", the only case where the migration step would not match the actual state of the schema were if we somehow run it manually, out of order, which would be incorrect usage of the migration.

I understand using actual schema modules and changesets in a seed script, but they should not be used in migrations.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately it looks like this will override some of the work that was done in the earlier migration that moved tasks to closed, because this is not checking for whether the issues are closed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joshsmith You are correct about checking for gi not closed. You could also check for task not closed, it would likely serve the same purpose, since presumably, the task is otherwise in sync with the issue.

On a similar note, my other migration should probably add a clause for archived. I'm not sure what the exact query would be, but it would likely involve a where: date_add(t.modified_at, 30, "day") > ^Date.utc_today somewhere in it.

I can't push the change myself due to not being home, but that should help.

end

def down do
alter table(:task_lists) do
remove :pull_requests
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
defmodule CodeCorps.Repo.Migrations.AddUniqueConstraintsToSpecificTaskLists do
@moduledoc false

use Ecto.Migration

def change do
# There is already a "task_lists_project_id_index", so we name explicitly

create unique_index(
"task_lists", [:project_id],
where: "done = true", name: "task_lists_project_id_done_index")
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!!


create unique_index(
"task_lists", [:project_id],
where: "pull_requests = true", name: "task_lists_project_id_pull_requests_index")

create unique_index(
"task_lists", [:project_id],
where: "inbox = true", name: "task_lists_project_id_inbox_index")
end
end
27 changes: 25 additions & 2 deletions priv/repo/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1486,7 +1486,9 @@ CREATE TABLE task_lists (
project_id bigint,
inserted_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL,
inbox boolean DEFAULT false
inbox boolean DEFAULT false,
done boolean DEFAULT false,
pull_requests boolean DEFAULT false
);


Expand Down Expand Up @@ -3072,13 +3074,34 @@ CREATE INDEX task_lists_inbox_index ON task_lists USING btree (inbox);
CREATE INDEX task_lists_order_index ON task_lists USING btree ("order");


--
-- Name: task_lists_project_id_done_index; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX task_lists_project_id_done_index ON task_lists USING btree (project_id) WHERE (done = true);


--
-- Name: task_lists_project_id_inbox_index; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX task_lists_project_id_inbox_index ON task_lists USING btree (project_id) WHERE (inbox = true);


--
-- Name: task_lists_project_id_index; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX task_lists_project_id_index ON task_lists USING btree (project_id);


--
-- Name: task_lists_project_id_pull_requests_index; Type: INDEX; Schema: public; Owner: -
--

CREATE UNIQUE INDEX task_lists_project_id_pull_requests_index ON task_lists USING btree (project_id) WHERE (pull_requests = true);


--
-- Name: task_skills_skill_id_index; Type: INDEX; Schema: public; Owner: -
--
Expand Down Expand Up @@ -3844,5 +3867,5 @@ ALTER TABLE ONLY users
-- PostgreSQL database dump complete
--

INSERT INTO "schema_migrations" (version) VALUES (20160723215749), (20160804000000), (20160804001111), (20160805132301), (20160805203929), (20160808143454), (20160809214736), (20160810124357), (20160815125009), (20160815143002), (20160816020347), (20160816034021), (20160817220118), (20160818000944), (20160818132546), (20160820113856), (20160820164905), (20160822002438), (20160822004056), (20160822011624), (20160822020401), (20160822044612), (20160830081224), (20160830224802), (20160911233738), (20160912002705), (20160912145957), (20160918003206), (20160928232404), (20161003185918), (20161019090945), (20161019110737), (20161020144622), (20161021131026), (20161031001615), (20161121005339), (20161121014050), (20161121043941), (20161121045709), (20161122015942), (20161123081114), (20161123150943), (20161124085742), (20161125200620), (20161126045705), (20161127054559), (20161205024856), (20161207112519), (20161209192504), (20161212005641), (20161214005935), (20161215052051), (20161216051447), (20161218005913), (20161219160401), (20161219163909), (20161220141753), (20161221085759), (20161226213600), (20161231063614), (20170102130055), (20170102181053), (20170104113708), (20170104212623), (20170104235423), (20170106013143), (20170115035159), (20170115230549), (20170121014100), (20170131234029), (20170201014901), (20170201025454), (20170201035458), (20170201183258), (20170220032224), (20170224233516), (20170226050552), (20170228085250), (20170308214128), (20170308220713), (20170308222552), (20170313130611), (20170318032449), (20170318082740), (20170324194827), (20170424215355), (20170501225441), (20170505224222), (20170526095401), (20170602000208), (20170622205732), (20170626231059), (20170628092119), (20170628213609), (20170629183404), (20170630140136), (20170706132431), (20170707213648), (20170711122252), (20170717092127), (20170725060612), (20170727052644), (20170731130121), (20170814131722), (20170913114958), (20170921014405), (20170925214512), (20170925230419), (20170926134646), (20170927100300), (20170928234412), (20171003134956), (20171003225853), (20171006063358), (20171006161407), (20171012215106), (20171012221231), (20171016125229), (20171016125516), (20171016223356), (20171016235656), (20171017235433), (20171019191035), (20171025184225), (20171026010933), (20171027061833), (20171028011642), (20171028173508), (20171030182857), (20171031232023), (20171031234356), (20171101023309), (20171104013543);
INSERT INTO "schema_migrations" (version) VALUES (20160723215749), (20160804000000), (20160804001111), (20160805132301), (20160805203929), (20160808143454), (20160809214736), (20160810124357), (20160815125009), (20160815143002), (20160816020347), (20160816034021), (20160817220118), (20160818000944), (20160818132546), (20160820113856), (20160820164905), (20160822002438), (20160822004056), (20160822011624), (20160822020401), (20160822044612), (20160830081224), (20160830224802), (20160911233738), (20160912002705), (20160912145957), (20160918003206), (20160928232404), (20161003185918), (20161019090945), (20161019110737), (20161020144622), (20161021131026), (20161031001615), (20161121005339), (20161121014050), (20161121043941), (20161121045709), (20161122015942), (20161123081114), (20161123150943), (20161124085742), (20161125200620), (20161126045705), (20161127054559), (20161205024856), (20161207112519), (20161209192504), (20161212005641), (20161214005935), (20161215052051), (20161216051447), (20161218005913), (20161219160401), (20161219163909), (20161220141753), (20161221085759), (20161226213600), (20161231063614), (20170102130055), (20170102181053), (20170104113708), (20170104212623), (20170104235423), (20170106013143), (20170115035159), (20170115230549), (20170121014100), (20170131234029), (20170201014901), (20170201025454), (20170201035458), (20170201183258), (20170220032224), (20170224233516), (20170226050552), (20170228085250), (20170308214128), (20170308220713), (20170308222552), (20170313130611), (20170318032449), (20170318082740), (20170324194827), (20170424215355), (20170501225441), (20170505224222), (20170526095401), (20170602000208), (20170622205732), (20170626231059), (20170628092119), (20170628213609), (20170629183404), (20170630140136), (20170706132431), (20170707213648), (20170711122252), (20170717092127), (20170725060612), (20170727052644), (20170731130121), (20170814131722), (20170913114958), (20170921014405), (20170925214512), (20170925230419), (20170926134646), (20170927100300), (20170928234412), (20171003134956), (20171003225853), (20171006063358), (20171006161407), (20171012215106), (20171012221231), (20171016125229), (20171016125516), (20171016223356), (20171016235656), (20171017235433), (20171019191035), (20171025184225), (20171026010933), (20171027061833), (20171028011642), (20171028173508), (20171030182857), (20171031232023), (20171031234356), (20171101023309), (20171104013543), (20171106045740), (20171106050209), (20171106103153);

121 changes: 116 additions & 5 deletions test/lib/code_corps/model/task_list_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ defmodule CodeCorps.TaskListTest do
use CodeCorps.ModelCase

alias CodeCorps.TaskList
alias Ecto.Changeset

@valid_attrs %{name: "some content", position: 42}
@invalid_attrs %{}
Expand All @@ -16,12 +17,122 @@ defmodule CodeCorps.TaskListTest do
refute changeset.valid?
end

test "is not inbox by default" do
test "defaults :done to 'false'" do
{:ok, record} =
%TaskList{}
|> TaskList.changeset(@valid_attrs)
|> CodeCorps.Repo.insert
%TaskList{} |> TaskList.changeset(@valid_attrs) |> Repo.insert
assert record.done == false
end

test "defaults :inbox to 'false'" do
{:ok, record} =
%TaskList{} |> TaskList.changeset(@valid_attrs) |> Repo.insert
assert record.inbox == false
end

test "defaults :pull_requests to 'false'" do
{:ok, record} =
%TaskList{} |> TaskList.changeset(@valid_attrs) |> Repo.insert
assert record.pull_requests == false
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@snewcomer Your assertion here was refute record.pull_requests, but that one would have passed even if record.pull_requests == nil, so we want a more explicit one.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦‍♂️

end

describe "create_changeset" do
test "casts done" do
attrs = @valid_attrs |> Map.merge(%{done: true})
changeset = %TaskList{} |> TaskList.create_changeset(attrs)
assert changeset |> Changeset.get_change(:done) == true
end

test "casts inbox" do
attrs = @valid_attrs |> Map.merge(%{inbox: true})
changeset = %TaskList{} |> TaskList.create_changeset(attrs)
assert changeset |> Changeset.get_change(:inbox) == true
end

test "casts pull_requests" do
attrs = @valid_attrs |> Map.merge(%{pull_requests: true})
changeset = %TaskList{} |> TaskList.create_changeset(attrs)
assert changeset |> Changeset.get_change(:pull_requests) == true
end

test "requires done" do
attrs = @valid_attrs |> Map.merge(%{done: nil})
changeset = %TaskList{} |> TaskList.create_changeset(attrs)
refute changeset.valid?
assert changeset |> Map.get(:errors) |> Keyword.get(:done)
end

test "requires inbox" do
attrs = @valid_attrs |> Map.merge(%{inbox: nil})
changeset = %TaskList{} |> TaskList.create_changeset(attrs)
refute changeset.valid?
assert changeset |> Map.get(:errors) |> Keyword.get(:inbox)
end

test "requires pull_requests" do
attrs = @valid_attrs |> Map.merge(%{pull_requests: nil})
changeset = %TaskList{} |> TaskList.create_changeset(attrs)
refute changeset.valid?
assert changeset |> Map.get(:errors) |> Keyword.get(:pull_requests)
end

test "ensures a unique 'done' task list per project" do
%{id: project_id} = insert(:project)
attrs = @valid_attrs |> Map.merge(%{done: true})

{:ok, _task_list} =
%TaskList{}
|> TaskList.create_changeset(attrs)
|> Changeset.put_change(:project_id, project_id)
|> Repo.insert

{:error, changeset} =
%TaskList{}
|> TaskList.create_changeset(attrs)
|> Changeset.put_change(:project_id, project_id)
|> Repo.insert

refute changeset.valid?
assert changeset |> Map.get(:errors) |> Keyword.get(:done)
end

test "ensures a unique 'inbox' task list per project" do
%{id: project_id} = insert(:project)
attrs = @valid_attrs |> Map.merge(%{inbox: true})

{:ok, _task_list} =
%TaskList{}
|> TaskList.create_changeset(attrs)
|> Changeset.put_change(:project_id, project_id)
|> Repo.insert

{:error, changeset} =
%TaskList{}
|> TaskList.create_changeset(attrs)
|> Changeset.put_change(:project_id, project_id)
|> Repo.insert

refute changeset.valid?
assert changeset |> Map.get(:errors) |> Keyword.get(:inbox)
end

test "ensures a unique 'pull_requests' task list per project" do
%{id: project_id} = insert(:project)
attrs = @valid_attrs |> Map.merge(%{pull_requests: true})

{:ok, _task_list} =
%TaskList{}
|> TaskList.create_changeset(attrs)
|> Changeset.put_change(:project_id, project_id)
|> Repo.insert

{:error, changeset} =
%TaskList{}
|> TaskList.create_changeset(attrs)
|> Changeset.put_change(:project_id, project_id)
|> Repo.insert

refute record.inbox
refute changeset.valid?
assert changeset |> Map.get(:errors) |> Keyword.get(:pull_requests)
end
end
end
2 changes: 2 additions & 0 deletions test/lib/code_corps_web/views/task_list_view_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ defmodule CodeCorpsWeb.TaskListViewTest do
expected_json = %{
"data" => %{
"attributes" => %{
"done" => task_list.done,
"inbox" => task_list.inbox,
"name" => task_list.name,
"order" => 1000,
"pull-requests" => task_list.pull_requests,
"inserted-at" => task_list.inserted_at,
"updated-at" => task_list.updated_at,
},
Expand Down