chore(make): adds basic workflow tasks

* Adds tasks for formatting, linting, and testing.
* Vendors flutter to a specific version.

Some refinement is needed and we will need to explore how to get the Atom IDE support for dart and flutter to play nice with the Vendored flutter version.

Closes #2

Change-Id: I7a8f90951d06dc2646962f09ab9181a888e9735e
diff --git a/.analysis_options b/.analysis_options
new file mode 100644
index 0000000..427c5c3
--- /dev/null
+++ b/.analysis_options
@@ -0,0 +1,3 @@
+analyzer:
+  exclude:
+    - deps/*
diff --git a/.gitignore b/.gitignore
index 1f8d8c1..887d277 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,9 @@
-/.jiri
\ No newline at end of file
+/.jiri
+deps
+.atom/
+.idea
+.packages
+.pub/
+build/
+ios/.generated/
+packages
diff --git a/FLUTTER_VERSION b/FLUTTER_VERSION
new file mode 100644
index 0000000..61c3673
--- /dev/null
+++ b/FLUTTER_VERSION
@@ -0,0 +1 @@
+199f24ad3ddde9ff6291ec0b6b42972c677fcc7d
diff --git a/Makefile b/Makefile
index 2d387e0..3dffd14 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,48 @@
+MAKEFLAGS += --warn-undefined-variables
+SHELL := /bin/bash
 
-.PHONY:
+.SHELLFLAGS := -eu -o pipefail -c
+.DEFAULT_GOAL := all
+.SUFFIXES:
+
+DIRNAME := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
+FLUTTER_BIN := $(DIRNAME)/deps/flutter/bin
+DART_BIN := $(FLUTTER_BIN)/cache/dart-sdk/bin
+PATH := $(FLUTTER_BIN):$(DART_BIN):$(PATH)
+
+.PHONY: all
+all: deps/flutter
+	@true # silences watch, do not remove.
+
+deps/flutter:
+	git clone https://github.com/flutter/flutter.git -b alpha $@
+	cd $@ && git checkout $(shell echo -e `cat FLUTTER_VERSION`)
+	flutter doctor
+	@touch $@
+
+.PHONY: clean
 clean:
 	@true
 
-.PHONY:
-test:
-	@true
+.PHONY: depclean
+depclean:
+	@rm -rf deps/flutter
+
+.PHONY: packages
+packages: examples/todos/packages
+
+examples/todos/packages: examples/todos/pubspec.yaml deps/flutter
+	cd examples/todos && pub get
+	@touch $@
+
+.PHONY: analyze
+analyze: deps/flutter packages
+	cd examples/todos/ && flutter analyze
+
+.PHONY: test
+test: packages analyze deps/flutter
+	cd examples/todos/ && flutter test
+
+.PHONY: fmt
+fmt: packages deps/flutter
+	cd examples/todos/ && dartfmt --overwrite lib
diff --git a/examples/todos/.gitignore b/examples/todos/.gitignore
deleted file mode 100644
index 14c7d4c..0000000
--- a/examples/todos/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-.DS_Store
-.atom/
-.idea
-.packages
-.pub/
-build/
-ios/.generated/
-packages
-pubspec.lock
diff --git a/examples/todos/pubspec.lock b/examples/todos/pubspec.lock
new file mode 100644
index 0000000..fb60dbd
--- /dev/null
+++ b/examples/todos/pubspec.lock
@@ -0,0 +1,328 @@
+# Generated by pub
+# See http://pub.dartlang.org/doc/glossary.html#lockfile
+packages:
+  analyzer:
+    description:
+      name: analyzer
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.27.4-alpha.6"
+  args:
+    description:
+      name: args
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.13.4+2"
+  async:
+    description:
+      name: async
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.11.0"
+  barback:
+    description:
+      name: barback
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.15.2+8"
+  boolean_selector:
+    description:
+      name: boolean_selector
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.1"
+  charcode:
+    description:
+      name: charcode
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.1.0"
+  collection:
+    description:
+      name: collection
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.7.0"
+  convert:
+    description:
+      name: convert
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.1.1"
+  crypto:
+    description:
+      name: crypto
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.9.2"
+  csslib:
+    description:
+      name: csslib
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.13.2"
+  file:
+    description:
+      name: file
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.1.0"
+  flutter:
+    description:
+      path: "../../deps/flutter/packages/flutter"
+      relative: true
+    source: path
+    version: "0.0.21"
+  flutter_driver:
+    description:
+      path: "../../deps/flutter/packages/flutter_driver"
+      relative: true
+    source: path
+    version: "0.0.1"
+  flutter_test:
+    description:
+      path: "../../deps/flutter/packages/flutter_test"
+      relative: true
+    source: path
+    version: "0.0.0"
+  glob:
+    description:
+      name: glob
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.1.2"
+  html:
+    description:
+      name: html
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.12.2+2"
+  http_multi_server:
+    description:
+      name: http_multi_server
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.0.1"
+  http_parser:
+    description:
+      name: http_parser
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "3.0.1"
+  intl:
+    description:
+      name: intl
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.12.7+1"
+  json_rpc_2:
+    description:
+      name: json_rpc_2
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.0.1"
+  logging:
+    description:
+      name: logging
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.11.3"
+  matcher:
+    description:
+      name: matcher
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.12.0+2"
+  meta:
+    description:
+      name: meta
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.12.1"
+  mime:
+    description:
+      name: mime
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.9.3"
+  mojo:
+    description:
+      name: mojo
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.4.20"
+  mojo_sdk:
+    description:
+      name: mojo_sdk
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.2.24"
+  mojo_services:
+    description:
+      name: mojo_services
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.4.27"
+  package_config:
+    description:
+      name: package_config
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.1.3"
+  path:
+    description:
+      name: path
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.3.9"
+  petitparser:
+    description:
+      name: petitparser
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.5.3"
+  plugin:
+    description:
+      name: plugin
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.2.0"
+  pool:
+    description:
+      name: pool
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.2.4"
+  pub_semver:
+    description:
+      name: pub_semver
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.2.4"
+  quiver:
+    description:
+      name: quiver
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.21.4"
+  shelf:
+    description:
+      name: shelf
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.6.5+2"
+  shelf_static:
+    description:
+      name: shelf_static
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.2.3+4"
+  shelf_web_socket:
+    description:
+      name: shelf_web_socket
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.2.1"
+  sky_engine:
+    description:
+      path: "../../deps/flutter/bin/cache/pkg/sky_engine"
+      relative: true
+    source: path
+    version: "0.0.99"
+  sky_services:
+    description:
+      path: "../../deps/flutter/bin/cache/pkg/sky_services"
+      relative: true
+    source: path
+    version: "0.0.99"
+  source_map_stack_trace:
+    description:
+      name: source_map_stack_trace
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.4"
+  source_maps:
+    description:
+      name: source_maps
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.10.1+1"
+  source_span:
+    description:
+      name: source_span
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.2.2"
+  stack_trace:
+    description:
+      name: stack_trace
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.6.5"
+  stream_channel:
+    description:
+      name: stream_channel
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.4.0"
+  string_scanner:
+    description:
+      name: string_scanner
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.1.4+1"
+  test:
+    description:
+      name: test
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.12.13+1"
+  typed_data:
+    description:
+      name: typed_data
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.1.3"
+  utf:
+    description:
+      name: utf
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.9.0+3"
+  uuid:
+    description:
+      name: uuid
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.5.0"
+  vector_math:
+    description:
+      name: vector_math
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.4.7"
+  vm_service_client:
+    description:
+      name: vm_service_client
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.2.2+1"
+  watcher:
+    description:
+      name: watcher
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.9.7+2"
+  web_socket_channel:
+    description:
+      name: web_socket_channel
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.3"
+  yaml:
+    description:
+      name: yaml
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.1.9"
+sdk: ">=1.16.0 <1.18.0"
diff --git a/examples/todos/pubspec.yaml b/examples/todos/pubspec.yaml
index 0fe0f08..566407c 100644
--- a/examples/todos/pubspec.yaml
+++ b/examples/todos/pubspec.yaml
@@ -3,10 +3,10 @@
 dependencies:
   uuid: 0.5.0
   flutter:
-    path:  ../../../../../../flutter/packages/flutter
+    path: ../../deps/flutter/packages/flutter
 dev_dependencies:
   test: any
   flutter_test:
-    path: ../../../../../../flutter/packages/flutter_test
+    path: ../../deps/flutter/packages/flutter_test
   flutter_driver:
-    path: ../../../../../../flutter/packages/flutter_driver
+    path: ../../deps/flutter/packages/flutter_driver
diff --git a/examples/todos/test/unit_test.dart b/examples/todos/test/unit_test.dart
new file mode 100644
index 0000000..6f938ea
--- /dev/null
+++ b/examples/todos/test/unit_test.dart
@@ -0,0 +1,11 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import 'package:test/test.dart';
+
+void main() {
+  test('this is a unit test', () {
+    expect(42, 42);
+  });
+}