Skip to content

Commit

Permalink
CircleCI support (#2359) (#2808)
Browse files Browse the repository at this point in the history
* #2359 Add Circle CI support

- Create Conan + CircleCI project template using command new
- Create Conan + CircleCI project template using API

Signed-off-by: Uilian Ries <uilianries@gmail.com>

* #2359 Validate CircleCI support

- Test CircleCI template

Signed-off-by: Uilian Ries <uilianries@gmail.com>
  • Loading branch information
uilianries authored and memsharded committed Apr 27, 2018
1 parent af34031 commit 10aedbc
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 9 deletions.
7 changes: 5 additions & 2 deletions conans/client/cmd/new.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ def test(self):

def cmd_new(ref, header=False, pure_c=False, test=False, exports_sources=False, bare=False,
visual_versions=None, linux_gcc_versions=None, linux_clang_versions=None, osx_clang_versions=None,
shared=None, upload_url=None, gitignore=None, gitlab_gcc_versions=None, gitlab_clang_versions=None):
shared=None, upload_url=None, gitignore=None, gitlab_gcc_versions=None, gitlab_clang_versions=None,
circleci_gcc_versions=None, circleci_clang_versions=None, circleci_osx_versions=None):
try:
tokens = ref.split("@")
name, version = tokens[0].split("/")
Expand Down Expand Up @@ -284,5 +285,7 @@ def cmd_new(ref, header=False, pure_c=False, test=False, exports_sources=False,
files.update(ci_get_files(name, version, user, channel, visual_versions,
linux_gcc_versions, linux_clang_versions,
osx_clang_versions, shared, upload_url,
gitlab_gcc_versions, gitlab_clang_versions))
gitlab_gcc_versions, gitlab_clang_versions,
circleci_gcc_versions, circleci_clang_versions,
circleci_osx_versions))
return files
147 changes: 144 additions & 3 deletions conans/client/cmd/new_ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,96 @@
<<: *build-template
"""

circleci = """
version: 2
.conan-steps: &conan-steps
steps:
- checkout
- run:
name: Update Conan package
command: |
chmod +x .circleci/install.sh
.circleci/install.sh
- run:
name: Build recipe
command: |
chmod +x .circleci/run.sh
.circleci/run.sh
environment:
CONAN_REFERENCE: "{name}/{version}"
CONAN_USERNAME: "{user}"
CONAN_CHANNEL: "{channel}"
{upload}
jobs:
{configs}
{workflow}
"""

circleci_config_gcc = """
gcc-{name}:
docker:
- image: lasote/conangcc{name}
environment:
- CONAN_GCC_VERSIONS: "{version}"
<<: *conan-steps
"""

circleci_config_clang = """
clang-{name}:
docker:
- image: lasote/conanclang{name}
environment:
- CONAN_CLANG_VERSIONS: "{version}"
<<: *conan-steps
"""

circleci_config_osx = """
xcode-{name}:
macos:
xcode: "{name}"
environment:
- CONAN_APPLE_CLANG_VERSIONS: "{version}"
<<: *conan-steps
"""

circleci_install = """
#!/bin/bash
set -e
set -x
SUDO=sudo
if [[ "$(uname -s)" == 'Darwin' ]]; then
brew update || brew update
brew install cmake || true
SUDO=
fi
$SUDO pip install conan --upgrade
$SUDO pip install conan_package_tools
conan user
"""

circleci_run = """
#!/bin/bash
set -e
set -x
python build.py
"""

circleci_workflow = """
workflows:
version: 2
build_and_test:
jobs:
{jobs}
"""

circleci_job = """ - {job}
"""

def get_build_py(name, shared):
shared = 'shared_option_name="{}:shared"'.format(name) if shared else ""
Expand Down Expand Up @@ -224,15 +314,50 @@ def get_gitlab(name, version, user, channel, linux_gcc_versions, linux_clang_ver
configs=configs, upload=upload)}
return files

def get_circleci(name, version, user, channel, linux_gcc_versions, linux_clang_versions,
osx_clang_versions, upload_url):
config = []
jobs = []

if linux_gcc_versions:
for gcc in linux_gcc_versions:
gcc_name = gcc.replace(".", "")
config.append(circleci_config_gcc.format(version=gcc, name=gcc_name))
jobs.append(circleci_job.format(job='gcc-{}'.format(gcc_name)))

if linux_clang_versions:
for clang in linux_clang_versions:
clang_name = clang.replace(".", "")
config.append(circleci_config_clang.format(version=clang, name=clang_name))
jobs.append(circleci_job.format(job='clang-{}'.format(clang_name)))

xcode_map = {"8.1": "8.3.3",
"9.0": "9.0"}
for apple_clang in osx_clang_versions:
osx_name = xcode_map[apple_clang]
config.append(circleci_config_osx.format(name=osx_name, version=apple_clang))
jobs.append(circleci_job.format(job='xcode-{}'.format(osx_name)))

configs = "".join(config)
workflow = circleci_workflow.format(jobs="".join(jobs))
upload = ('CONAN_UPLOAD: "%s"\n' % upload_url) if upload_url else ""
files = {".circleci/config.yml": circleci.format(name=name, version=version, user=user, channel=channel,
configs=configs, workflow=workflow, upload=upload),
".circleci/install.sh": circleci_install,
".circleci/run.sh": circleci_run}
return files


def ci_get_files(name, version, user, channel, visual_versions, linux_gcc_versions,
linux_clang_versions, osx_clang_versions, shared, upload_url, gitlab_gcc_versions,
gitlab_clang_versions):
gitlab_clang_versions, circleci_gcc_versions, circleci_clang_versions, circleci_osx_versions):
if shared and not (visual_versions or linux_gcc_versions or linux_clang_versions or
osx_clang_versions or gitlab_gcc_versions or gitlab_clang_versions):
osx_clang_versions or gitlab_gcc_versions or gitlab_clang_versions or
circleci_gcc_versions or circleci_clang_versions or circleci_osx_versions):
raise ConanException("Trying to specify 'shared' in CI, but no CI system specified")
if not (visual_versions or linux_gcc_versions or linux_clang_versions or osx_clang_versions or
gitlab_gcc_versions or gitlab_clang_versions):
gitlab_gcc_versions or gitlab_clang_versions or circleci_gcc_versions or
circleci_clang_versions or circleci_osx_versions):
return {}
gcc_versions = ["4.9", "5", "6", "7"]
clang_versions = ["3.9", "4.0"]
Expand All @@ -242,12 +367,18 @@ def ci_get_files(name, version, user, channel, visual_versions, linux_gcc_versio
linux_gcc_versions = gcc_versions
if gitlab_gcc_versions is True:
gitlab_gcc_versions = gcc_versions
if circleci_gcc_versions is True:
circleci_gcc_versions = gcc_versions
if linux_clang_versions is True:
linux_clang_versions = clang_versions
if gitlab_clang_versions is True:
gitlab_clang_versions = clang_versions
if circleci_clang_versions is True:
circleci_clang_versions = clang_versions
if osx_clang_versions is True:
osx_clang_versions = ["7.3", "8.1", "9.0"]
if circleci_osx_versions is True:
circleci_osx_versions = ["8.1", "9.0"]
if not visual_versions:
visual_versions = []
if not linux_gcc_versions:
Expand All @@ -260,6 +391,12 @@ def ci_get_files(name, version, user, channel, visual_versions, linux_gcc_versio
gitlab_gcc_versions = []
if not gitlab_clang_versions:
gitlab_clang_versions = []
if not circleci_gcc_versions:
circleci_gcc_versions = []
if not circleci_clang_versions:
circleci_clang_versions = []
if not circleci_osx_versions:
circleci_osx_versions = []
files = {"build.py": get_build_py(name, shared)}
if linux_gcc_versions or osx_clang_versions or linux_clang_versions:
files.update(get_travis(name, version, user, channel, linux_gcc_versions,
Expand All @@ -269,6 +406,10 @@ def ci_get_files(name, version, user, channel, visual_versions, linux_gcc_versio
files.update(get_gitlab(name, version, user, channel, gitlab_gcc_versions,
gitlab_clang_versions, upload_url))

if circleci_gcc_versions or circleci_clang_versions or circleci_osx_versions:
files.update(get_circleci(name, version, user, channel, circleci_gcc_versions,
circleci_clang_versions, circleci_osx_versions, upload_url))

if visual_versions:
files.update(get_appveyor(name, version, user, channel, visual_versions, upload_url))

Expand Down
14 changes: 13 additions & 1 deletion conans/client/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ def new(self, *args):
parser.add_argument("-ciglc", "--ci-gitlab-clang", action='store_true',
default=False,
help='Generate GitLab files for linux clang')
parser.add_argument("-ciccg", "--ci-circleci-gcc", action='store_true',
default=False,
help='Generate CicleCI files for linux gcc')
parser.add_argument("-ciccc", "--ci-circleci-clang", action='store_true',
default=False,
help='Generate CicleCI files for linux clang')
parser.add_argument("-cicco", "--ci-circleci-osx", action='store_true',
default=False,
help='Generate CicleCI files for OSX apple-clang')
parser.add_argument("-gi", "--gitignore", action='store_true', default=False,
help='Generate a .gitignore with the known patterns to excluded')
parser.add_argument("-ciu", "--ci-upload-url",
Expand All @@ -157,7 +166,10 @@ def new(self, *args):
osx_clang_versions=args.ci_travis_osx, shared=args.ci_shared,
upload_url=args.ci_upload_url,
gitlab_gcc_versions=args.ci_gitlab_gcc,
gitlab_clang_versions=args.ci_gitlab_clang)
gitlab_clang_versions=args.ci_gitlab_clang,
circleci_gcc_versions=args.ci_circleci_gcc,
circleci_clang_versions=args.ci_circleci_clang,
circleci_osx_versions=args.ci_circleci_osx)

def test(self, *args):
"""Test a package consuming it from a conanfile.py with a test() method. This command
Expand Down
8 changes: 6 additions & 2 deletions conans/client/conan_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,8 @@ def _init_manager(self):
def new(self, name, header=False, pure_c=False, test=False, exports_sources=False, bare=False,
cwd=None, visual_versions=None, linux_gcc_versions=None, linux_clang_versions=None,
osx_clang_versions=None, shared=None, upload_url=None, gitignore=None,
gitlab_gcc_versions=None, gitlab_clang_versions=None):
gitlab_gcc_versions=None, gitlab_clang_versions=None,
circleci_gcc_versions=None, circleci_clang_versions=None, circleci_osx_versions=None):
from conans.client.cmd.new import cmd_new
cwd = os.path.abspath(cwd or os.getcwd())
files = cmd_new(name, header=header, pure_c=pure_c, test=test,
Expand All @@ -245,7 +246,10 @@ def new(self, name, header=False, pure_c=False, test=False, exports_sources=Fals
osx_clang_versions=osx_clang_versions, shared=shared,
upload_url=upload_url, gitignore=gitignore,
gitlab_gcc_versions=gitlab_gcc_versions,
gitlab_clang_versions=gitlab_clang_versions)
gitlab_clang_versions=gitlab_clang_versions,
circleci_gcc_versions=circleci_gcc_versions,
circleci_clang_versions=circleci_clang_versions,
circleci_osx_versions=circleci_osx_versions)

save_files(cwd, files)
for f in sorted(files):
Expand Down
43 changes: 42 additions & 1 deletion conans/test/command/new_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def new_without_test(self):

def new_ci_test(self):
client = TestClient()
client.run('new MyPackage/1.3@myuser/testing -cis -ciw -cilg -cilc -cio -ciglg -ciglc -ciu=myurl')
client.run('new MyPackage/1.3@myuser/testing -cis -ciw -cilg -cilc -cio -ciglg -ciglc -ciccg -ciccc -cicco -ciu=myurl')
root = client.current_folder
build_py = load(os.path.join(root, "build.py"))
self.assertIn('builder.add_common_builds(shared_option_name="MyPackage:shared")',
Expand All @@ -120,6 +120,9 @@ def new_ci_test(self):
self.assertNotIn('apple_clang_versions=', build_py)
self.assertNotIn('gitlab_gcc_versions=', build_py)
self.assertNotIn('gitlab_clang_versions=', build_py)
self.assertNotIn('circleci_gcc_versions=', build_py)
self.assertNotIn('circleci_clang_versions=', build_py)
self.assertNotIn('circleci_osx_versions=', build_py)

appveyor = load(os.path.join(root, "appveyor.yml"))
self.assertIn("CONAN_UPLOAD: \"myurl\"", appveyor)
Expand All @@ -145,6 +148,13 @@ def new_ci_test(self):
self.assertIn('CONAN_CHANNEL: "testing"', gitlab)
self.assertIn('CONAN_GCC_VERSIONS: "5"', gitlab)

circleci = load(os.path.join(root, ".circleci", "config.yml"))
self.assertIn("CONAN_UPLOAD: \"myurl\"", circleci)
self.assertIn('CONAN_REFERENCE: "MyPackage/1.3"', circleci)
self.assertIn('CONAN_USERNAME: "myuser"', circleci)
self.assertIn('CONAN_CHANNEL: "testing"', circleci)
self.assertIn('CONAN_GCC_VERSIONS: "5"', circleci)

def new_ci_test_partial(self):
client = TestClient()
root = client.current_folder
Expand All @@ -158,6 +168,7 @@ def new_ci_test_partial(self):
self.assertTrue(os.path.exists(os.path.join(root, ".travis/run.sh")))
self.assertFalse(os.path.exists(os.path.join(root, "appveyor.yml")))
self.assertFalse(os.path.exists(os.path.join(root, ".gitlab-ci.yml")))
self.assertFalse(os.path.exists(os.path.join(root, ".circleci/config.yml")))

client = TestClient()
root = client.current_folder
Expand All @@ -168,6 +179,7 @@ def new_ci_test_partial(self):
self.assertFalse(os.path.exists(os.path.join(root, ".travis/run.sh")))
self.assertTrue(os.path.exists(os.path.join(root, "appveyor.yml")))
self.assertFalse(os.path.exists(os.path.join(root, ".gitlab-ci.yml")))
self.assertFalse(os.path.exists(os.path.join(root, ".circleci/config.yml")))

client = TestClient()
root = client.current_folder
Expand All @@ -178,6 +190,7 @@ def new_ci_test_partial(self):
self.assertTrue(os.path.exists(os.path.join(root, ".travis/run.sh")))
self.assertFalse(os.path.exists(os.path.join(root, "appveyor.yml")))
self.assertFalse(os.path.exists(os.path.join(root, ".gitlab-ci.yml")))
self.assertFalse(os.path.exists(os.path.join(root, ".circleci/config.yml")))

client = TestClient()
root = client.current_folder
Expand All @@ -193,6 +206,7 @@ def new_ci_test_partial(self):
self.assertFalse(os.path.exists(os.path.join(root, ".travis/install.sh")))
self.assertFalse(os.path.exists(os.path.join(root, ".travis/run.sh")))
self.assertFalse(os.path.exists(os.path.join(root, "appveyor.yml")))
self.assertFalse(os.path.exists(os.path.join(root, ".circleci/config.yml")))

client = TestClient()
root = client.current_folder
Expand All @@ -203,3 +217,30 @@ def new_ci_test_partial(self):
self.assertFalse(os.path.exists(os.path.join(root, ".travis/install.sh")))
self.assertFalse(os.path.exists(os.path.join(root, ".travis/run.sh")))
self.assertFalse(os.path.exists(os.path.join(root, "appveyor.yml")))
self.assertFalse(os.path.exists(os.path.join(root, ".circleci/config.yml")))

client = TestClient()
root = client.current_folder
client.run('new MyPackage/1.3@myuser/testing -ciccg')
self.assertTrue(os.path.exists(os.path.join(root, "build.py")))
self.assertTrue(os.path.exists(os.path.join(root, ".circleci/config.yml")))
self.assertTrue(os.path.exists(os.path.join(root, ".circleci/install.sh")))
self.assertTrue(os.path.exists(os.path.join(root, ".circleci/run.sh")))
self.assertFalse(os.path.exists(os.path.join(root, ".gitlab-ci.yml")))
self.assertFalse(os.path.exists(os.path.join(root, ".travis.yml")))
self.assertFalse(os.path.exists(os.path.join(root, ".travis/install.sh")))
self.assertFalse(os.path.exists(os.path.join(root, ".travis/run.sh")))
self.assertFalse(os.path.exists(os.path.join(root, "appveyor.yml")))

client = TestClient()
root = client.current_folder
client.run('new MyPackage/1.3@myuser/testing -ciccc')
self.assertTrue(os.path.exists(os.path.join(root, "build.py")))
self.assertTrue(os.path.exists(os.path.join(root, ".circleci/config.yml")))
self.assertTrue(os.path.exists(os.path.join(root, ".circleci/install.sh")))
self.assertTrue(os.path.exists(os.path.join(root, ".circleci/run.sh")))
self.assertFalse(os.path.exists(os.path.join(root, ".gitlab-ci.yml")))
self.assertFalse(os.path.exists(os.path.join(root, ".travis.yml")))
self.assertFalse(os.path.exists(os.path.join(root, ".travis/install.sh")))
self.assertFalse(os.path.exists(os.path.join(root, ".travis/run.sh")))
self.assertFalse(os.path.exists(os.path.join(root, "appveyor.yml")))

0 comments on commit 10aedbc

Please sign in to comment.