Skip to content

Commit

Permalink
Move to CircleCI for Builds and Tests (project-chip#631)
Browse files Browse the repository at this point in the history
* Initial CircleCI

* Restyled by shellharden

* Restyled by shfmt

* Appeasing our restyle.io overlord

* testing

* Trying to figure out this run_if.sh problem

* Feedback from Rob W

* Restyled by shfmt

* Typo

* Updating restyled to match editorconfig tab spacing

* Updating devcontainer

* Restyled by shfmt

* Adding simple restyle merge

* Restyled by shellharden

Co-authored-by: Restyled.io <commits@restyled.io>
  • Loading branch information
woody-apple and restyled-commits authored May 14, 2020
1 parent 423c8db commit a923ce7
Show file tree
Hide file tree
Showing 45 changed files with 1,388 additions and 326 deletions.
1 change: 1 addition & 0 deletions .circleci/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
config.yml linguist-generated
1 change: 1 addition & 0 deletions .circleci/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.tmp/
95 changes: 95 additions & 0 deletions .circleci/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Set SHELL to 'strict mode' without using .SHELLFLAGS for max compatibility.
# See https://fieldnotes.tech/how-to-shell-for-compatible-makefiles/
SHELL := /usr/bin/env bash -euo pipefail -c

# CONFIG is the name of the make target someone
# would invoke to update the main config file (config.yml).
CONFIG ?= ci-config
# VERIFY is the name of the make target someone
# would invoke to verify the config file.
VERIFY ?= ci-verify

CIRCLECI := circleci --skip-update-check
ifeq ($(DEBUG_CIRCLECI_CLI),YES)
CIRCLECI += --debug
endif

# For config processing, always refer to circleci.com not self-hosted circleci,
# because self-hosted does not currently support the necessary API.
CIRCLECI_CLI_HOST := https://circleci.com
export CIRCLECI_CLI_HOST

# Set up some documentation/help message variables.
# We do not attempt to install the CircleCI CLI from this Makefile.
CCI_INSTALL_LINK := https://circleci.com/docs/2.0/local-cli/\#installation
CCI_INSTALL_MSG := Please install CircleCI CLI. See $(CCI_INSTALL_LINK)
CCI_VERSION := $(shell $(CIRCLECI) version 2> /dev/null)
ifeq ($(CCI_VERSION),)
# Attempting to use the CLI fails with installation instructions.
CIRCLECI := echo '$(CCI_INSTALL_MSG)'; exit 1; \#
endif

SOURCE_DIR := config
SOURCE_YML := $(shell [ ! -d $(SOURCE_DIR) ] || find $(SOURCE_DIR) -name '*.yml')
CONFIG_SOURCE := Makefile $(SOURCE_YML) | $(SOURCE_DIR)
OUT := config.yml
TMP := .tmp/config-processed
CONFIG_PACKED := .tmp/config-packed

default: help

help:
@echo "Usage:"
@echo " make $(CONFIG): recompile config.yml from $(SOURCE_DIR)/"
@echo " make $(VERIFY): verify that config.yml is a true mapping from $(SOURCE_DIR)/"
@echo
@echo "Diagnostics:"
@[ -z "$(CCI_VERSION)" ] || echo " circleci-cli version $(CCI_VERSION)"
@[ -n "$(CCI_VERSION)" ] || echo " $(CCI_INSTALL_MSG)"

$(SOURCE_DIR):
@echo No source directory $(SOURCE_DIR) found.; exit 1

# Make sure our .tmp dir exists.
$(shell [ -d .tmp ] || mkdir .tmp)

.PHONY: $(CONFIG)
$(CONFIG): $(OUT)

.PHONY: $(VERIFY)
$(VERIFY): config-up-to-date
@$(CIRCLECI) config validate $(OUT)

define GENERATED_FILE_HEADER
### ***
### WARNING: DO NOT manually EDIT or MERGE this file, it is generated by 'make $(CONFIG)'.
### INSTEAD: Edit or merge the source in $(SOURCE_DIR)/ then run 'make $(CONFIG)'.
### ***
endef
export GENERATED_FILE_HEADER

# GEN_CONFIG writes the config to a temporary file. If the whole process succeeds,
# it them moves that file to $@. This makes it an atomic operation, so if it fails
# make doesn't consider a half-baked file up to date.
define GEN_CONFIG
@$(CIRCLECI) config pack $(SOURCE_DIR) > $(CONFIG_PACKED)
@echo "$$GENERATED_FILE_HEADER" > $@.tmp || { rm -f $@; exit 1; }
@$(CIRCLECI) config process $(CONFIG_PACKED) >> $@.tmp || { rm -f $@.tmp; exit 1; }
@mv -f $@.tmp $@
endef

$(OUT): $(CONFIG_SOURCE)
$(GEN_CONFIG)
@echo "$@ updated"

$(TMP): $(CONFIG_SOURCE)
$(GEN_CONFIG)

.PHONY: config-up-to-date
config-up-to-date: $(TMP) # Note this must not depend on $(OUT)!
@if diff -w $(OUT) $<; then \
echo "Generated $(OUT) is up to date!"; \
else \
echo "Generated $(OUT) is out of date, run make $(CONFIG) to update."; \
exit 1; \
fi
130 changes: 130 additions & 0 deletions .circleci/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# How to use CircleCI multi-file config

This README and the Makefile should be in your `.circleci` directory,
in the root of your repository.
All path references in this README assume we are in this `.circleci` directory.

The `Makefile` in this directory generates `./config.yml` in CircleCI 2.0 syntax,
from the tree rooted at `./config/`, which contains files in CircleCI 2.0 or 2.1 syntax.


## Quickstart

The basic workflow is:

- Edit source files in `./config/`
- When you are done, run `make ci-config` to update `./config.yml`
- Commit this entire `.circleci` directory, including that generated file together.
- Run `make ci-verify` to ensure the current `./config.yml` is up to date with the source.

When merging this `.circleci` directory:

- Do not merge the generated `./config.yml` file, instead:
- Merge the source files under `./config/`, and then
- Run `make ci-config` to re-generate the merged `./config.yml`

And that's it, for more detail, read on!


## How does it work, roughly?

CircleCI supports [generating a single config file from many],
using the `$ circleci config pack` command.
It also supports [expanding 2.1 syntax to 2.0 syntax]
using the `$ circleci config process` command.
We use these two commands, stitched together using the `Makefile`
to implement the workflow.

[generating a single config file from many]: https://circleci.com/docs/2.0/local-cli/#packing-a-config
[expanding 2.1 syntax to 2.0 syntax]: https://circleci.com/docs/2.0/local-cli/#processing-a-config


## Prerequisites

You will need the [CircleCI CLI tool] installed and working,
at least version `0.1.5607`.
You can [download this tool directly from GitHub Releases].

```
$ circleci version
0.1.5607+f705856
```

[CircleCI CLI tool]: https://circleci.com/docs/2.0/local-cli/
[download this tool directly from GitHub Releases]: https://github.com/CircleCI-Public/circleci-cli/releases


## Updating the config source

Before making changes, be sure to understand the layout
of the `./config/` file tree, as well as circleci 2.1 syntax.
See the [Syntax and layout] section below.

To update the config, you should edit, add or remove files
in the `./config/` directory,
and then run `make ci-config`.
If that's successful,
you should then commit every `*.yml` file in the tree rooted in this directory.
That is: you should commit both the source under `./config/`
and the generated file `./config.yml` at the same time, in the same commit.
The included git pre-commit hook will help with this.
Do not edit the `./config.yml` file directly, as you will lose your changes
next time `make ci-config` is run.

[Syntax and layout]: #syntax-and-layout


### Verifying `./config.yml`

To check whether or not the current `./config.yml` is up to date with the source
and valid, run `$ make ci-verify`.
Note that `$ make ci-verify` should be run in CI,
in case not everyone has the git pre-commit hook set up correctly.


#### Example shell session

```sh
$ make ci-config
config.yml updated
$ git add -A . # The -A makes sure to include deletions/renames etc.
$ git commit -m "ci: blah blah blah"
Changes detected in .circleci/, running 'make -C .circleci ci-verify'
--> Generated config.yml is up to date!
--> Config file at config.yml is valid.
```


### Syntax and layout

It is important to understand the layout of the config directory.
Read the documentation on [packing a config] for a full understanding
of how multiple YAML files are merged by the circleci CLI tool.

[packing a config]: https://circleci.com/docs/2.0/local-cli/#packing-a-config

Here is an example file tree (with comments added afterwards):

```sh
$ tree .
.
├── Makefile
├── README.md # This file.
├── config # The source code for config.yml is rooted here.
│   ├── @config.yml # Files beginning with @ are treated specially by `circleci config pack`
│   ├── commands # Subdirectories of config become top-level keys.
│   │   └── go_test.yml # Filenames (minus .yml) become top-level keys under
│   │   └── go_build.yml # their parent (in this case "commands").
│ │ # The contents of go_test.yml therefore are placed at: .commands.go_test:
│   └── jobs # jobs also becomes a top-level key under config...
│   ├── build.yml # ...and likewise filenames become keys under their parent.
│   └── test.yml
└── config.yml # The generated file in 2.0 syntax.
```

About those `@` files... Preceding a filename with `@`
indicates to `$ circleci config pack` that the contents of this YAML file
should be at the top-level, rather than underneath a key named after their filename.
This naming convention is unfortunate as it breaks autocompletion in bash,
but there we go.

Loading

0 comments on commit a923ce7

Please sign in to comment.