Language Guide: Dart
This document is a walkthrough of a sample Dart project setup on CircleCI. The project cherry-picks number_guesser
and number_thinker
code from the Write HTTP clients & servers tutorial.
We assume you have a basic working knowledge of CircleCI and associated terminology. If not, visit our Getting Started docs.
Quickstart
Repository: circleci-dart-demo
Builds: circleci-dart-demo on CircleCI
- Find the full configuration at the bottom of this document or in the repository linked above.
- Copy that config into
.circleci/config.yml
in your project’s root directory. - Modify as needed.
The CircleCI config does the following:
-
It runs the tests in a Docker container.
- The
test
job uses thegoogle/dart
Docker image as its execution image. - The tests use the junitreporter package to produce JUnit XML output for CircleCI’s test metadata feature, which in turn supports features such as test summary, intelligent test splitting, and insights data/metrics.
- The
-
After tests run, it builds executables for deployment.
-
build-docker
uses Google’sdart-runtime
as a base to build a Docker container. There’s a commented section that pushes to DockerHub. It’s there as an example. - The other three jobs compile native executables on macOS, Windows, and Linux VMs.
-
-
All jobs use dependency caching.
- The cache keys change according to the
pubspec.lock
file and thearch
of the system. If thepubspec.lock
file changes, the cache is invalidated and a new cache is created. -
~/.pub-cache
and.dart_tool
folders are cached by default on Linux and macOS.~/AppData/Local/Pub/Cache
if Windows. - For Dart projects that have it, you’ll probably also want to add and cache the
.packages
folder in the main project directory.
- The cache keys change according to the
If you fork this project and want to push to DockerHub, this project assumes a context called dart-docker
with the following variables & keys:
KEY | VALUE |
---|---|
DOCKER_TAG | The tag/repository for your image |
DOCKER_LOGIN | Your Docker login |
DOCKER_PWD | Your Docker password |
See the config and modify as needed for your use case.
Config walkthrough
The first section of the file defines common items. The order in which things are defined in a CircleCI configuration doesn’t matter - we have laid it out this way for readability.
version: 2.1
orbs:
win: circleci/windows@2.4.0
-
Config Version: Current is
2.1
. Unless using a CircleCI Server installation, we recommend using 2.1. - Orbs: CircleCI offers orbs, which are packaged, templatized, and reusable configuration. Here, we include the Windows orb to make use of a pre-defined execution environment later on.
commands:
dependencies:
description: "Download dependencies and setup global packages"
parameters:
shell:
type: string
default: "/bin/bash --login -eo pipefail"
pub-cache:
type: string
default: "~/.pub-cache"
steps:
- checkout
- restore_cache:
keys:
- v1.4-dependencies-{{ arch }}-{{ checksum "pubspec.lock" }}
- v1.4-dependencies-{{ arch }}-
- run:
name: Download deps
shell: << parameters.shell >>
command: pub get
- run:
name: Get junitreporter
shell: << parameters.shell >>
command: pub global activate junitreport
- save_cache:
key: v1.4-dependencies-{{ arch }}-{{ checksum "pubspec.lock" }}
paths:
- .dart_tool
- << parameters.pub-cache >>
native-build:
description: "Runs the dart2native command to build native executable for machine. Artifacts executable"
parameters:
shell:
type: string
default: "/bin/bash --login -eo pipefail"
steps:
- run:
name: Native compile
shell: << parameters.shell >>
command: dart2native bin/server.dart -o circleci_dart_demo.exe
- store_artifacts:
path: circleci_dart_demo.exe
- CircleCI offers reusable configuration syntax, which is what our orbs are built off of. Under
commands
, we define a few parameterized commands that run the same sequence of steps.-
dependencies
checks out the code and restores/saves a dependency cache (Dart packages downloaded from last build). -
native-build
uses thedart2native
command to compile a native executable for each operating system and then artifacts it, making it available to download from the job details. - In both commands, we take parameters to override a cache path and shell for different jobs. Dart’s package cache is in a different location in Windows, and it also uses a different shell (Powershell).
-
workflows:
version: 2.1
test-and-build:
jobs:
- test
- build-mac:
requires:
- test
- build-windows:
requires:
- test
- build-linux:
requires:
- test
- build-docker:
# Uncomment/modify context to use secrets (e.g., DockerHub credentials, etc.)
#context: dart-docker
requires:
- test
- In the
workflows
section, we define a workflow calledtest-and-build
and define which jobs are run. - Each of the
build-*
jobs depend ontest
passing, which is set by therequires
key. - The commented line for
build-docker
uses adart-docker
context. See links to resources at the bottom of this document.
jobs:
test:
docker:
- image: google/dart:2.9.1
auth:
username: mydockerhub-user
password: $DOCKERHUB_PASSWORD # context / project UI env-var reference
steps:
- dependencies:
shell: "/bin/bash -eo pipefail"
- run:
name: Make folder for test results
command: mkdir -p test-results/dart-tests
- run:
name: Run tests
command: pub run test --reporter json | tojunit --output test-results/dart-tests/circleci_dart_demo_test-report.xml
- store_test_results:
path: test-results
- In the
jobs
section, we define each of the jobs we configured to run in the workflow. The firsttest
job runs tests and uses thejunitreporter
to output results in JUnit XML format.
build-mac:
macos:
xcode: "11.3.0"
steps:
- run:
name: Install Dart SDK
command: |
HOMEBREW_NO_AUTO_UPDATE=1 brew tap dart-lang/dart
HOMEBREW_NO_AUTO_UPDATE=1 brew install dart
- dependencies
- native-build
build-windows:
executor: win/default
steps:
- run:
name: Install Dart SDK
command: choco install dart-sdk
- dependencies:
shell: "powershell.exe"
pub-cache: "~/AppData/Local/Pub/Cache"
- native-build:
shell: "powershell.exe"
build-linux:
machine: true
steps:
- run:
name: Install Dart SDK
shell: /bin/bash --login -eo pipefail
command: |
# Setup repo & signing key
sudo apt update
sudo apt install apt-transport-https
sudo sh -c 'wget -qO- https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
sudo sh -c 'wget -qO- https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
# Update again and install
sudo apt update
sudo apt install dart
# Set PATH in profile for downstream commands
echo "export PATH=$PATH:/usr/lib/dart/bin" >> $BASH_ENV
- dependencies
- native-build
- Each of the
build-*
jobs uses different setup steps to install the Dart runtime and executables. - Then as defined above, we make use of the same
dependencies
andnative-build
commands, overriding parameters when needed.
build-docker:
docker:
- image: cimg/base:2020.08
auth:
username: mydockerhub-user
password: $DOCKERHUB_PASSWORD # context / project UI env-var reference
steps:
- setup_remote_docker
- checkout
- run:
name: Build & tag Docker image
command: docker build -t circleci/circleci-dart-demo -t circleci/circle-dart-demo:${CIRCLE_SHA1} .
# Uncomment the following to use DOCKER_* env variables defined in context set above (line 79) and push to DockerHub
#- run:
#name: Build & tag Docker image
#command: docker build -t ${DOCKER_TAG} -t ${DOCKER_TAG}:${CIRCLE_SHA1} .
#- run:
#name: Login to DockerHub and push
#command: |
# echo $DOCKER_PWD | docker login -u $DOCKER_LOGIN --password-stdin
# docker push ${DOCKER_TAG}
# docker push ${DOCKER_TAG}:${CIRCLE_SHA1}
- The final job builds a Docker image using Google’s
dart-runtime
as a base. - The commented section is code to build, tag, and push a Docker image according to environment variables defined in a context. It’s included as an example.
Full sample configuration
Below is the entirety of the file. Additional resources and links to supporting documentation can be found below.
# Author @mvxt
version: 2.1
#####################
# Common Definitions
#####################
# Orb declarations
orbs:
win: circleci/windows@2.4.0
# Simple YAML anchors
aliases:
- &project_dir "~/project"
commands:
dependencies:
description: "Download dependencies and setup global packages"
parameters:
shell:
type: string
default: "/bin/bash --login -eo pipefail"
pub-cache:
type: string
default: "~/.pub-cache"
steps:
- checkout
- restore_cache:
keys:
- v1.4-dependencies-{{ arch }}-{{ checksum "pubspec.lock" }}
- v1.4-dependencies-{{ arch }}-
- run:
name: Download deps
shell: << parameters.shell >>
command: pub get
- run:
name: Get junitreporter
shell: << parameters.shell >>
command: pub global activate junitreport
- save_cache:
key: v1.4-dependencies-{{ arch }}-{{ checksum "pubspec.lock" }}
paths:
- .dart_tool
- << parameters.pub-cache >>
native-build:
description: "Runs the dart2native command to build native executable for machine. Artifacts executable"
parameters:
shell:
type: string
default: "/bin/bash --login -eo pipefail"
steps:
- run:
name: Native compile
shell: << parameters.shell >>
command: dart2native bin/server.dart -o circleci_dart_demo.exe
- store_artifacts:
path: circleci_dart_demo.exe
###### ################
# Workflow definition
###### ################
workflows:
version: 2.1
test-and-build:
jobs:
- test
- build-mac:
requires:
- test
- build-windows:
requires:
- test
- build-linux:
requires:
- test
- build-docker:
# Uncomment/modify context to use secrets (e.g., DockerHub credentials, etc.)
#context: dart-docker
requires:
- test
##################
# Job Definitions
##################
jobs:
test:
docker:
- image: google/dart:2.9.1
auth:
username: mydockerhub-user
password: $DOCKERHUB_PASSWORD # context / project UI env-var reference
steps:
- dependencies:
shell: "/bin/bash -eo pipefail"
- run:
name: Make folder for test results
command: mkdir -p test-results/dart-tests
- run:
name: Run tests
command: pub run test --reporter json | tojunit --output test-results/dart-tests/circleci_dart_demo_test-report.xml
- store_test_results:
path: test-results
build-mac:
macos:
xcode: "11.3.0"
steps:
- run:
name: Install Dart SDK
command: |
HOMEBREW_NO_AUTO_UPDATE=1 brew tap dart-lang/dart
HOMEBREW_NO_AUTO_UPDATE=1 brew install dart
- dependencies
- native-build
build-windows:
executor: win/default
steps:
- run:
name: Install Dart SDK
command: choco install dart-sdk
- dependencies:
shell: "powershell.exe"
pub-cache: "~/AppData/Local/Pub/Cache"
- native-build:
shell: "powershell.exe"
build-linux:
machine: true
steps:
- run:
name: Install Dart SDK
shell: /bin/bash --login -eo pipefail
command: |
# Setup repo & signing key
sudo apt update
sudo apt install apt-transport-https
sudo sh -c 'wget -qO- https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
sudo sh -c 'wget -qO- https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
# Update again and install
sudo apt update
sudo apt install dart
# Set PATH in profile for downstream commands
echo "export PATH=$PATH:/usr/lib/dart/bin" >> $BASH_ENV
- dependencies
- native-build
build-docker:
docker:
- image: cimg/base:2020.08
auth:
username: mydockerhub-user
password: $DOCKERHUB_PASSWORD # context / project UI env-var reference
steps:
- setup_remote_docker
- checkout
- run:
name: Build & tag Docker image
command: docker build -t circleci/circleci-dart-demo -t circleci/circle-dart-demo:${CIRCLE_SHA1} .
# Uncomment the following to use DOCKER_* env variables defined in context set above (line 79) and push to DockerHub
#- run:
#name: Build & tag Docker image
#command: docker build -t ${DOCKER_TAG} -t ${DOCKER_TAG}:${CIRCLE_SHA1} .
#- run:
#name: Login to DockerHub and push
#command: |
# echo $DOCKER_PWD | docker login -u $DOCKER_LOGIN --password-stdin
# docker push ${DOCKER_TAG}
# docker push ${DOCKER_TAG}:${CIRCLE_SHA1}