Merge pull request #52 from ralphlange/devel/gh-actions

Add support for GitHub Actions
This commit is contained in:
Ralph Lange
2020-06-29 10:45:23 +02:00
committed by GitHub
9 changed files with 571 additions and 74 deletions

View File

@@ -37,6 +37,7 @@ skip_commits:
- '**/*.html' - '**/*.html'
- '**/*.md' - '**/*.md'
- '.travis.yml' - '.travis.yml'
- '.github/workflows/*'
#---------------------------------# #---------------------------------#
# additional packages # # additional packages #

156
.github/workflows/build-and-test.yml vendored Normal file
View File

@@ -0,0 +1,156 @@
name: ci-scripts build/test
on:
push:
branches: [ devel/gh-actions ]
env:
SETUP_PATH: .:.ci
SET: test01
VV: 1
BASE_RECURSIVE: NO
CMP: gcc
APT: re2c
CHOCO: re2c
BREW: re2c
jobs:
unit-test:
name: Unit tests on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-16.04, windows-2019, windows-2016, macos-10.15]
steps:
- uses: actions/checkout@v2
- name: Show initial environment
run: python cue-test.py env
- name: Run unit tests
run: python cue-test.py
build-linux:
name: ${{ matrix.cmp }} / ${{ matrix.configuration }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-16.04]
cmp: [gcc, clang]
configuration: [default, static, debug, static-debug]
steps:
- uses: actions/checkout@v2
- name: Prepare and compile dependencies
run: python cue.py prepare
- name: Build main module (example app)
run: python cue.py build
- name: Run main module tests
run: python cue.py test
- name: Collect and show test results
run: python cue.py test-results
build-macos:
name: ${{ matrix.cmp }} / ${{ matrix.configuration }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
strategy:
fail-fast: false
matrix:
os: [macos-10.15]
cmp: [clang]
configuration: [default, debug]
steps:
- uses: actions/checkout@v2
- name: Prepare and compile dependencies
run: python cue.py prepare
- name: Build main module (example app)
run: python cue.py build
- name: Run main module tests
run: python cue.py test
- name: Collect and show test results
run: python cue.py test-results
build-windows:
name: ${{ matrix.cmp }} / ${{ matrix.configuration }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
strategy:
fail-fast: false
matrix:
os: [windows-2019, windows-2016]
cmp: [gcc, vs2019, vs2017]
configuration: [default, static, debug, static-debug]
exclude:
- os: windows-2019
cmp: vs2017
- os: windows-2016
cmp: vs2019
steps:
- uses: actions/checkout@v2
- name: Prepare and compile dependencies
run: python cue.py prepare
- name: Build main module (example app)
run: python cue.py build
- name: Run main module tests
run: python cue.py test
- name: Collect and show test results
run: python cue.py test-results
build-rtems:
name: RTEMS${{ matrix.rtems }} / ${{ matrix.configuration }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
RTEMS: ${{ matrix.rtems }}
APT: re2c g++-mingw-w64-i686 g++-mingw-w64-x86-64 qemu-system-x86
strategy:
fail-fast: false
matrix:
os: [ubuntu-18.04]
cmp: [gcc]
configuration: [default, static, debug, static-debug]
rtems: ["4.9", "4.10"]
steps:
- uses: actions/checkout@v2
- name: Prepare and compile dependencies
run: python cue.py prepare
- name: Build main module (example app)
run: python cue.py build
- name: Run main module tests
run: python cue.py test
- name: Collect and show test results
run: python cue.py test-results
build-wine:
name: WINE${{ matrix.wine }} / ${{ matrix.configuration }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
WINE: ${{ matrix.wine }}
APT: re2c g++-mingw-w64-i686 g++-mingw-w64-x86-64
strategy:
fail-fast: false
matrix:
os: [ubuntu-18.04]
cmp: [gcc]
configuration: [default, static, debug, static-debug]
wine: [32, 64]
steps:
- uses: actions/checkout@v2
- name: Prepare and compile dependencies
run: python cue.py prepare
- name: Build main module (example app)
run: python cue.py build
- name: Run main module tests
run: python cue.py test
- name: Collect and show test results
run: python cue.py test-results

View File

@@ -1,6 +1,7 @@
<a target="_blank" href="http://semver.org">![Version][badge.version]</a> <a target="_blank" href="http://semver.org">![Version][badge.version]</a>
<a target="_blank" href="https://travis-ci.org/epics-base/ci-scripts">![Travis status][badge.travis]</a> <a target="_blank" href="https://travis-ci.org/epics-base/ci-scripts">![Travis status][badge.travis]</a>
<a target="_blank" href="https://ci.appveyor.com/project/epics-base/ci-scripts">![AppVeyor status][badge.appveyor]</a> <a target="_blank" href="https://ci.appveyor.com/project/epics-base/ci-scripts">![AppVeyor status][badge.appveyor]</a>
<a target="_blank" href="https://github.com/epics-base/ci-scripts/actions">![GitHub Actions status][badge.gh-actions]</a>
# Continuous Integration for EPICS Modules # Continuous Integration for EPICS Modules
@@ -58,12 +59,12 @@ levels as the example files.
### [Travis-CI](https://travis-ci.org/) ### [Travis-CI](https://travis-ci.org/)
- Five parallel runners on Linux/Windows (one runner on MacOS) - Five parallel runners on Linux/Windows (one runner on MacOS)
- Use different compilers (gcc, clang) - Ubuntu 12/14/16/18, MacOS 10.13, Windows Server v1809
- Use different gcc versions - Compile natively on Linux (different versions of gcc, clang)
- Cross-compile for Windows 32bit and 64bit using MinGW and WINE
- Cross-compile for RTEMS 4.9 and 4.10 (Base >= 3.15)
- Compile natively on MacOS (clang) - Compile natively on MacOS (clang)
- Compile natively on Windows (gcc/MinGW, Visual Studio 2017) - Compile natively on Windows (gcc/MinGW, Visual Studio 2017)
- Cross-compile for Windows 32bit and 64bit using MinGW and WINE
- Cross-compile for RTEMS 4.9 and 4.10 (Base >= 3.15)
- Built dependencies are cached (for faster builds). - Built dependencies are cached (for faster builds).
See specific See specific
@@ -72,8 +73,8 @@ for more details.
### [AppVeyor](https://www.appveyor.com/) ### [AppVeyor](https://www.appveyor.com/)
- One parallel runner (all builds are sequential) - One parallel runner (all builds are sequential)
- Use different compilers (Visual Studio, gcc/MinGW) - Windows Server 2012/2016/2019
- Use different Visual Studio versions: \ - Compile using gcc/MinGW or different Visual Studio versions: \
2008, 2010, 2012, 2013, 2015, 2017, 2019 2008, 2010, 2012, 2013, 2015, 2017, 2019
- Compile for Windows 32bit and 64bit - Compile for Windows 32bit and 64bit
- No useful caching available. - No useful caching available.
@@ -82,15 +83,30 @@ See specific
**[ci-scripts on AppVeyor README](appveyor/README.md)** **[ci-scripts on AppVeyor README](appveyor/README.md)**
for more details. for more details.
### [GitHub Actions](https://github.com/)
- 20 parallel runners on Linux/Windows (5 runners on MacOS)
- Ubuntu 16/18/20, MacOS 10.15, Windows Server 2016/2019
- Compile natively on Linux (gcc, clang)
- Compile natively on MacOS (clang)
- Compile natively on Windows (gcc/MinGW, Visual Studio 2017 & 2019)
- Cross-compile for Windows 32bit and 64bit using MinGW and WINE
- Cross-compile for RTEMS 4.9 and 4.10 (Base >= 3.15)
- Caching not supported by ci-scripts yet.
See specific
**[ci-scripts on GitHub Actions README](gh-actions/README.md)**
for more details.
## How to Use the CI-Scripts ## How to Use the CI-Scripts
1. Get an account on a supported CI service provider platform. 1. Get an account on a supported CI service provider platform
(e.g. [Travis-CI](https://travis-ci.org/), (e.g. [Travis-CI](https://travis-ci.org/),
[AppVeyor](https://www.appveyor.com/), ...) [AppVeyor](https://www.appveyor.com/), ...).
GitHub Actions does not require a separate account.
(More details in the specific README of the subdirectory.) (More details in the specific README of the subdirectory.)
2. In your Support Module, add this ci-scripts repository 2. In your module, add this ci-scripts repository
as a Git Submodule (name suggestion: `.ci`). as a Git Submodule (name suggestion: `.ci`).
```bash ```bash
git submodule add https://github.com/epics-base/ci-scripts .ci git submodule add https://github.com/epics-base/ci-scripts .ci
@@ -405,6 +421,7 @@ in file LICENSE that is included with this distribution.
[badge.version]: https://badge.fury.io/gh/epics-base%2Fci-scripts.svg [badge.version]: https://badge.fury.io/gh/epics-base%2Fci-scripts.svg
[badge.travis]: https://travis-ci.org/epics-base/ci-scripts.svg?branch=master [badge.travis]: https://travis-ci.org/epics-base/ci-scripts.svg?branch=master
[badge.appveyor]: https://ci.appveyor.com/api/projects/status/8b578alg974axvux?svg=true [badge.appveyor]: https://ci.appveyor.com/api/projects/status/8b578alg974axvux?svg=true
[badge.gh-actions]: https://github.com/epics-base/ci-scripts/workflows/ci-scripts%20build/test/badge.svg
[reddit.bash]: https://www.reddit.com/r/bash/comments/393oqv/why_is_the_version_of_bash_included_in_os_x_so_old/ [reddit.bash]: https://www.reddit.com/r/bash/comments/393oqv/why_is_the_version_of_bash_included_in_os_x_so_old/

View File

@@ -3,8 +3,8 @@
## Features ## Features
- One parallel runner (all builds are sequential) - One parallel runner (all builds are sequential)
- Use different compilers (Visual Studio, gcc/MinGW) - Windows Server 2012/2016/2019
- Use different Visual Studio versions: \ - Compile using gcc/MinGW or different Visual Studio versions: \
2008, 2010, 2012, 2013, 2015, 2017, 2019 2008, 2010, 2012, 2013, 2015, 2017, 2019
- Compile for Windows 32bit and 64bit - Compile for Windows 32bit and 64bit
- No useful caching available. - No useful caching available.

View File

@@ -31,6 +31,13 @@ if 'APPVEYOR' in os.environ:
elif re.match(r'^macOS', os.environ['APPVEYOR_BUILD_WORKER_IMAGE']): elif re.match(r'^macOS', os.environ['APPVEYOR_BUILD_WORKER_IMAGE']):
ci_os = 'osx' ci_os = 'osx'
if 'GITHUB_ACTIONS' in os.environ:
ci_service = 'github-actions'
if os.environ['RUNNER_OS'] == 'macOS':
ci_os = 'osx'
else:
ci_os = os.environ['RUNNER_OS'].lower()
def find_in_file(regex, filename): def find_in_file(regex, filename):
file = open(filename, "r") file = open(filename, "r")
@@ -324,8 +331,14 @@ class TestDefaultModuleURLs(unittest.TestCase):
@unittest.skipIf(ci_os != 'windows', 'VCVars test only applies to windows') @unittest.skipIf(ci_os != 'windows', 'VCVars test only applies to windows')
class TestVCVars(unittest.TestCase): class TestVCVars(unittest.TestCase):
def test_vcvars(self): def test_vcvars(self):
if ci_service == 'appveyor': if ci_service == 'travis':
os.environ['TRAVIS_COMPILER'] = 'vs2017'
else:
os.environ['CONFIGURATION'] = 'default' os.environ['CONFIGURATION'] = 'default'
if ci_service == 'github-actions' and os.environ['IMAGEOS'] == 'win16':
os.environ['CMP'] = 'vs2017'
else:
os.environ['CMP'] = 'vs2019'
cue.detect_context() cue.detect_context()
cue.with_vcvars('env') cue.with_vcvars('env')
@@ -676,7 +689,7 @@ class TestSetupForBuild(unittest.TestCase):
args = Namespace(paths=[]) args = Namespace(paths=[])
cue.building_base = True cue.building_base = True
if ci_os == 'windows': if ci_os == 'windows':
sp.check_call(['choco', 'install', 'make']) sp.check_call(['choco', 'install', 'make', 'strawberryperl', '-ry'])
def setUp(self): def setUp(self):
if ci_service == 'appveyor': if ci_service == 'appveyor':
@@ -726,10 +739,10 @@ class TestSetupForBuild(unittest.TestCase):
@unittest.skipIf(ci_os != 'windows', 'HostArchPlatform test only applies to windows') @unittest.skipIf(ci_os != 'windows', 'HostArchPlatform test only applies to windows')
def test_HostArchPlatform(self): def test_HostArchPlatform(self):
if ci_service == 'travis': if ci_service == 'appveyor':
platforms = ['x64']
else:
platforms = ['x86', 'x64'] platforms = ['x86', 'x64']
else:
platforms = ['x64']
for platform in platforms: for platform in platforms:
for cc in ['vs2019', 'gcc']: for cc in ['vs2019', 'gcc']:
cue.ci['platform'] = platform cue.ci['platform'] = platform
@@ -750,18 +763,17 @@ class TestSetupForBuild(unittest.TestCase):
self.assertTrue(re.search('-mingw$', os.environ['EPICS_HOST_ARCH']), self.assertTrue(re.search('-mingw$', os.environ['EPICS_HOST_ARCH']),
'EPICS_HOST_ARCH (found {0}) is not -mingw for {1} / {2}' 'EPICS_HOST_ARCH (found {0}) is not -mingw for {1} / {2}'
.format(os.environ['EPICS_HOST_ARCH'], cc, platform)) .format(os.environ['EPICS_HOST_ARCH'], cc, platform))
pattern = {'x86': 'mingw32', 'x64': 'mingw64'} if ci_service == 'appveyor':
self.assertTrue(re.search(pattern[platform], os.environ['PATH']), pattern = {'x86': 'mingw32', 'x64': 'mingw64'}
'Binary location for {0} not in PATH (found {1})' self.assertTrue(re.search(pattern[platform], os.environ['PATH']),
.format(pattern[platform], os.environ['PATH'])) 'Binary location for {0} not in PATH (found PATH = {1})'
.format(pattern[platform], os.environ['PATH']))
@unittest.skipIf(ci_os != 'windows', 'Strawberry perl test only applies to windows') @unittest.skipIf(ci_os != 'windows', 'Strawberry perl test only applies to windows')
def test_StrawberryInPathVS2019(self): def test_StrawberryInPath(self):
if 'APPVEYOR' in os.environ:
os.environ['CMP'] = 'vs2019'
cue.setup_for_build(self.args) cue.setup_for_build(self.args)
self.assertTrue(re.search('strawberry', os.environ['PATH'], flags=re.IGNORECASE), self.assertTrue(re.search('strawberry', os.environ['PATH'], flags=re.IGNORECASE),
'Strawberry Perl installed but location not in PATH (found {0})' 'Strawberry Perl location not in PATH (found PATH = {0})'
.format(os.environ['PATH'])) .format(os.environ['PATH']))
def setBase314(self, yesno): def setBase314(self, yesno):
@@ -827,5 +839,14 @@ if __name__ == "__main__":
if sys.argv[1:] == ['env']: if sys.argv[1:] == ['env']:
# testing with_vcvars # testing with_vcvars
[print(K, '=', V) for K, V in os.environ.items()] [print(K, '=', V) for K, V in os.environ.items()]
elif ci_os == 'windows' and sys.argv[1:] == ['findvs']:
from fnmatch import fnmatch
print('Available Visual Studio versions')
for base in (r'C:\Program Files (x86)', r'C:\Program Files'):
for root, dirs, files in os.walk(base):
for fname in files:
if fnmatch(fname, 'vcvarsall.bat'):
print('Found', os.path.join(root, fname))
sys.stdout.flush()
else: else:
unittest.main() unittest.main()

147
cue.py
View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
"""CI build script for Linux/MacOS/Windows on Travis/AppVeyor """CI build script for Linux/MacOS/Windows on Travis/AppVeyor/GitHub-Actions
""" """
from __future__ import print_function from __future__ import print_function
@@ -22,11 +22,10 @@ def detect_context():
ci['os'] = os.environ['TRAVIS_OS_NAME'] ci['os'] = os.environ['TRAVIS_OS_NAME']
ci['platform'] = 'x64' ci['platform'] = 'x64'
ci['compiler'] = os.environ['TRAVIS_COMPILER'] ci['compiler'] = os.environ['TRAVIS_COMPILER']
if ci['os'] == 'windows': ci['choco'] += ['strawberryperl']
ci['choco'] += ['strawberryperl'] if re.match(r'^vs', ci['compiler']):
if re.match(r'^vs', ci['compiler']): # Only Visual Studio 2017 available
# Only Visual Studio 2017 available ci['compiler'] = 'vs2017'
ci['compiler'] = 'vs2017'
if 'BCFG' in os.environ: if 'BCFG' in os.environ:
buildconfig = os.environ['BCFG'].lower() buildconfig = os.environ['BCFG'].lower()
@@ -43,6 +42,24 @@ def detect_context():
ci['compiler'] = os.environ['CMP'] ci['compiler'] = os.environ['CMP']
buildconfig = os.environ['CONFIGURATION'].lower() buildconfig = os.environ['CONFIGURATION'].lower()
if 'GITHUB_ACTIONS' in os.environ:
ci['service'] = 'github-actions'
if os.environ['RUNNER_OS'] == 'macOS':
ci['os'] = 'osx'
else:
ci['os'] = os.environ['RUNNER_OS'].lower()
ci['platform'] = 'x64'
if 'CMP' in os.environ:
ci['compiler'] = os.environ['CMP']
ci['choco'] += ['strawberryperl']
if 'BCFG' in os.environ:
buildconfig = os.environ['BCFG'].lower()
if re.search('static', buildconfig):
ci['static'] = True
if re.search('debug', buildconfig):
ci['debug'] = True
if 'STATIC' in os.environ: if 'STATIC' in os.environ:
print("{0}WARNING: Variable 'STATIC' not supported anymore; use 'BCFG' instead{1}" print("{0}WARNING: Variable 'STATIC' not supported anymore; use 'BCFG' instead{1}"
.format(ANSI_RED, ANSI_RESET)) .format(ANSI_RED, ANSI_RESET))
@@ -52,11 +69,6 @@ def detect_context():
.format(ANSI_RED, buildconfig, ANSI_RESET)) .format(ANSI_RED, buildconfig, ANSI_RESET))
sys.stdout.flush() sys.stdout.flush()
if re.search('static', buildconfig):
ci['static'] = True
if re.search('debug', buildconfig):
ci['debug'] = True
if ci['static']: if ci['static']:
ci['configuration'] = 'static' ci['configuration'] = 'static'
else: else:
@@ -74,6 +86,9 @@ def detect_context():
if 'APT' in os.environ: if 'APT' in os.environ:
ci['apt'].extend(os.environ['APT'].split()) ci['apt'].extend(os.environ['APT'].split())
if 'BREW' in os.environ:
ci['homebrew'].extend(os.environ['BREW'].split())
ci['test'] = True ci['test'] = True
if 'TEST' in os.environ and os.environ['TEST'].lower() == 'no': if 'TEST' in os.environ and os.environ['TEST'].lower() == 'no':
ci['test'] = False ci['test'] = False
@@ -130,6 +145,7 @@ def clear_lists():
ci['scriptsdir'] = '' ci['scriptsdir'] = ''
ci['choco'] = ['make'] ci['choco'] = ['make']
ci['apt'] = [] ci['apt'] = []
ci['homebrew'] = []
clear_lists() clear_lists()
@@ -153,11 +169,16 @@ ANSI_CLEAR = "\033[0K"
# Travis log fold control # Travis log fold control
# from https://github.com/travis-ci/travis-rubies/blob/build/build.sh # from https://github.com/travis-ci/travis-rubies/blob/build/build.sh
# GitHub Actions fold control
# from https://github.com/actions/toolkit/blob/master/docs/commands.md#group-and-ungroup-log-lines
def fold_start(tag, title): def fold_start(tag, title):
if ci['service'] == 'travis': if ci['service'] == 'travis':
print('travis_fold:start:{0}{1}{2}{3}' print('travis_fold:start:{0}{1}{2}{3}'
.format(tag, ANSI_YELLOW, title, ANSI_RESET)) .format(tag, ANSI_YELLOW, title, ANSI_RESET))
elif ci['service'] == 'github-actions':
print('::group::{0}{1}{2}'
.format(ANSI_YELLOW, title, ANSI_RESET))
elif ci['service'] == 'appveyor': elif ci['service'] == 'appveyor':
print('{0}===== \\/ \\/ \\/ ===== START: {1} ====={2}' print('{0}===== \\/ \\/ \\/ ===== START: {1} ====={2}'
.format(ANSI_YELLOW, title, ANSI_RESET)) .format(ANSI_YELLOW, title, ANSI_RESET))
@@ -168,6 +189,9 @@ def fold_end(tag, title):
if ci['service'] == 'travis': if ci['service'] == 'travis':
print('\ntravis_fold:end:{0}\r' print('\ntravis_fold:end:{0}\r'
.format(tag), end='') .format(tag), end='')
elif ci['service'] == 'github-actions':
print('::endgroup::'
.format(ANSI_YELLOW, title, ANSI_RESET))
elif ci['service'] == 'appveyor': elif ci['service'] == 'appveyor':
print('{0}----- /\\ /\\ /\\ ----- END: {1} -----{2}' print('{0}----- /\\ /\\ /\\ ----- END: {1} -----{2}'
.format(ANSI_YELLOW, title, ANSI_RESET)) .format(ANSI_YELLOW, title, ANSI_RESET))
@@ -181,7 +205,7 @@ elif 'HOME' in os.environ:
homedir = os.getenv('HOME') homedir = os.getenv('HOME')
cachedir = os.path.join(homedir, '.cache') cachedir = os.path.join(homedir, '.cache')
toolsdir = os.path.join(homedir, '.tools') toolsdir = os.path.join(homedir, '.tools')
rtemsdir = os.path.join(homedir, '.rtems') rtemsdir = r'/home/travis/.rtems' # Preliminary, until the next generation of toolchain
if 'CACHEDIR' in os.environ: if 'CACHEDIR' in os.environ:
cachedir = os.environ['CACHEDIR'] cachedir = os.environ['CACHEDIR']
@@ -189,8 +213,10 @@ if 'CACHEDIR' in os.environ:
vcvars_table = { vcvars_table = {
# https://en.wikipedia.org/wiki/Microsoft_Visual_Studio#History # https://en.wikipedia.org/wiki/Microsoft_Visual_Studio#History
'vs2019': [r'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat'], 'vs2019': [r'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat',
r'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat'],
'vs2017': [r'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat', 'vs2017': [r'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat',
r'C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat',
r'C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat'], r'C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat'],
'vs2015': [r'C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat'], 'vs2015': [r'C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat'],
'vs2013': [r'C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat'], 'vs2013': [r'C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat'],
@@ -551,32 +577,34 @@ def setup_for_build(args):
global is_base314, has_test_results, is_make3 global is_base314, has_test_results, is_make3
dllpaths = [] dllpaths = []
logger.debug('Setting up the build environment')
if ci['os'] == 'windows': if ci['os'] == 'windows':
if ci['service'] == 'appveyor': if os.path.exists(r'C:\Strawberry\perl\bin'):
if ci['compiler'] == 'vs2019': # Put strawberry perl in front of the PATH (so that Git Perl is further behind)
# put strawberry perl in the PATH logger.debug('Adding Strawberry Perl in front of the PATH')
os.environ['PATH'] = os.pathsep.join([os.path.join(r'C:\Strawberry\perl\site\bin'), os.environ['PATH'] = os.pathsep.join([r'C:\Strawberry\c\bin',
os.path.join(r'C:\Strawberry\perl\bin'), r'C:\Strawberry\perl\site\bin',
os.environ['PATH']]) r'C:\Strawberry\perl\bin',
if ci['compiler'] == 'gcc':
if 'INCLUDE' not in os.environ:
os.environ['INCLUDE'] = ''
if ci['platform'] == 'x86':
os.environ['INCLUDE'] = os.pathsep.join(
[r'C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\include',
os.environ['INCLUDE']])
os.environ['PATH'] = os.pathsep.join([r'C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin',
os.environ['PATH']])
elif ci['platform'] == 'x64':
os.environ['INCLUDE'] = os.pathsep.join(
[r'C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\include',
os.environ['INCLUDE']])
os.environ['PATH'] = os.pathsep.join([r'C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin',
os.environ['PATH']])
if ci['service'] == 'travis':
os.environ['PATH'] = os.pathsep.join([r'C:\Strawberry\perl\site\bin', r'C:\Strawberry\perl\bin',
os.environ['PATH']]) os.environ['PATH']])
if ci['service'] == 'appveyor' and ci['compiler'] == 'gcc':
logger.debug('Adding AppVeyor MSYS2/MinGW installation to PATH and INCLUDE')
if 'INCLUDE' not in os.environ:
os.environ['INCLUDE'] = ''
if ci['platform'] == 'x86':
os.environ['INCLUDE'] = os.pathsep.join(
[r'C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\include',
os.environ['INCLUDE']])
os.environ['PATH'] = os.pathsep.join([r'C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin',
os.environ['PATH']])
elif ci['platform'] == 'x64':
os.environ['INCLUDE'] = os.pathsep.join(
[r'C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\include',
os.environ['INCLUDE']])
os.environ['PATH'] = os.pathsep.join([r'C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin',
os.environ['PATH']])
# Find BASE location # Find BASE location
if not building_base: if not building_base:
with open(os.path.join(cachedir, 'RELEASE.local'), 'r') as f: with open(os.path.join(cachedir, 'RELEASE.local'), 'r') as f:
@@ -588,6 +616,8 @@ def setup_for_build(args):
else: else:
places['EPICS_BASE'] = '.' places['EPICS_BASE'] = '.'
logger.debug('Using EPICS Base at %s', places['EPICS_BASE'])
detect_epics_host_arch() detect_epics_host_arch()
if ci['os'] == 'windows': if ci['os'] == 'windows':
@@ -611,6 +641,7 @@ def setup_for_build(args):
with open(cfg_base_version) as myfile: with open(cfg_base_version) as myfile:
if 'BASE_3_14=YES' in myfile.read(): if 'BASE_3_14=YES' in myfile.read():
is_base314 = True is_base314 = True
logger.debug('Check if EPICS Base is a 3.14 series: %s', is_base314)
if not is_base314: if not is_base314:
rules_build = os.path.join(places['EPICS_BASE'], 'configure', 'RULES_BUILD') rules_build = os.path.join(places['EPICS_BASE'], 'configure', 'RULES_BUILD')
@@ -623,6 +654,7 @@ def setup_for_build(args):
# Check make version # Check make version
if re.match(r'^GNU Make 3', sp.check_output(['make', '-v']).decode('ascii')): if re.match(r'^GNU Make 3', sp.check_output(['make', '-v']).decode('ascii')):
is_make3 = True is_make3 = True
logger.debug('Check if make is a 3.x series: %s', is_make3)
# apparently %CD% is handled automagically # apparently %CD% is handled automagically
os.environ['TOP'] = os.getcwd() os.environ['TOP'] = os.getcwd()
@@ -781,14 +813,17 @@ CROSS_COMPILER_TARGET_ARCHS += windows-x64-mingw''')
RTEMS_VERSION={0} RTEMS_VERSION={0}
RTEMS_BASE={1}'''.format(os.environ['RTEMS'], rtemsdir)) RTEMS_BASE={1}'''.format(os.environ['RTEMS'], rtemsdir))
# Base 3.15 doesn't have -qemu target architecture # Patch Base 3.15 that doesn't have -qemu target architecture
qemu_suffix = '' if not os.path.exists(os.path.join(places['EPICS_BASE'], 'configure', 'os',
if os.path.exists(os.path.join(places['EPICS_BASE'], 'configure', 'os',
'CONFIG.Common.RTEMS-pc386-qemu')): 'CONFIG.Common.RTEMS-pc386-qemu')):
qemu_suffix = '-qemu' print('Adding RTEMS-pc386-qemu target to Base in {0}'.format(places['EPICS_BASE']))
sys.stdout.flush()
sp.check_call(['patch', '-p1', '-i',
os.path.join(ci['scriptsdir'], 'add-RTEMS-pc368-qemu-target.patch')],
cwd=places['EPICS_BASE'])
with open(os.path.join(places['EPICS_BASE'], 'configure', 'CONFIG_SITE'), 'a') as f: with open(os.path.join(places['EPICS_BASE'], 'configure', 'CONFIG_SITE'), 'a') as f:
f.write(''' f.write('''
CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386{0}'''.format(qemu_suffix)) CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386-qemu''')
host_ccmplr_name = re.sub(r'^([a-zA-Z][^-]*(-[a-zA-Z][^-]*)*)+(-[0-9.]|)$', r'\1', ci['compiler']) host_ccmplr_name = re.sub(r'^([a-zA-Z][^-]*(-[a-zA-Z][^-]*)*)+(-[0-9.]|)$', r'\1', ci['compiler'])
host_cmplr_ver_suffix = re.sub(r'^([a-zA-Z][^-]*(-[a-zA-Z][^-]*)*)+(-[0-9.]|)$', r'\3', ci['compiler']) host_cmplr_ver_suffix = re.sub(r'^([a-zA-Z][^-]*(-[a-zA-Z][^-]*)*)+(-[0-9.]|)$', r'\3', ci['compiler'])
@@ -819,20 +854,24 @@ CMPLR_CLASS = clang''')
CC = {0}{2} CC = {0}{2}
CCC = {1}{2}'''.format(host_ccmplr_name, host_cppcmplr_name, host_cmplr_ver_suffix)) CCC = {1}{2}'''.format(host_ccmplr_name, host_cppcmplr_name, host_cmplr_ver_suffix))
# Add additional flags to CONFIG_SITE # Add additional settings to CONFIG_SITE
flags_text = '' extra_config = ''
if 'USR_CPPFLAGS' in os.environ: if 'USR_CPPFLAGS' in os.environ:
flags_text += ''' extra_config += '''
USR_CPPFLAGS += {0}'''.format(os.environ['USR_CPPFLAGS']) USR_CPPFLAGS += {0}'''.format(os.environ['USR_CPPFLAGS'])
if 'USR_CFLAGS' in os.environ: if 'USR_CFLAGS' in os.environ:
flags_text += ''' extra_config += '''
USR_CFLAGS += {0}'''.format(os.environ['USR_CFLAGS']) USR_CFLAGS += {0}'''.format(os.environ['USR_CFLAGS'])
if 'USR_CXXFLAGS' in os.environ: if 'USR_CXXFLAGS' in os.environ:
flags_text += ''' extra_config += '''
USR_CXXFLAGS += {0}'''.format(os.environ['USR_CXXFLAGS']) USR_CXXFLAGS += {0}'''.format(os.environ['USR_CXXFLAGS'])
if flags_text: if ci['service'] == 'github-actions' and ci['os'] == 'windows':
extra_config += '''
PERL = C:/Strawberry/perl/bin/perl -CSD'''
if extra_config:
with open(os.path.join(places['EPICS_BASE'], 'configure', 'CONFIG_SITE'), 'a') as f: with open(os.path.join(places['EPICS_BASE'], 'configure', 'CONFIG_SITE'), 'a') as f:
f.write(flags_text) f.write(extra_config)
fold_end('set.up.epics_build', 'Configuring EPICS build system') fold_end('set.up.epics_build', 'Configuring EPICS build system')
@@ -841,7 +880,7 @@ USR_CXXFLAGS += {0}'''.format(os.environ['USR_CXXFLAGS'])
if ci['os'] == 'windows' and ci['choco']: if ci['os'] == 'windows' and ci['choco']:
fold_start('install.choco', 'Installing CHOCO packages') fold_start('install.choco', 'Installing CHOCO packages')
sp.check_call(['choco', 'install'] + ci['choco']) sp.check_call(['choco', 'install'] + ci['choco'] + ['-y', '--limitoutput', '--no-progress'])
fold_end('install.choco', 'Installing CHOCO packages') fold_end('install.choco', 'Installing CHOCO packages')
if ci['os'] == 'linux' and ci['apt']: if ci['os'] == 'linux' and ci['apt']:
@@ -849,6 +888,11 @@ USR_CXXFLAGS += {0}'''.format(os.environ['USR_CXXFLAGS'])
sp.check_call(['sudo', 'apt-get', '-y', 'install'] + ci['apt']) sp.check_call(['sudo', 'apt-get', '-y', 'install'] + ci['apt'])
fold_end('install.apt', 'Installing APT packages') fold_end('install.apt', 'Installing APT packages')
if ci['os'] == 'osx' and ci['homebrew']:
fold_start('install.homebrew', 'Installing Homebrew packages')
sp.check_call(['brew', 'install'] + ci['homebrew'])
fold_end('install.homebrew', 'Installing Homebrew packages')
if ci['os'] == 'linux' and 'RTEMS' in os.environ: if ci['os'] == 'linux' and 'RTEMS' in os.environ:
tar_name = 'i386-rtems{0}-trusty-20171203-{0}.tar.bz2'.format(os.environ['RTEMS']) tar_name = 'i386-rtems{0}-trusty-20171203-{0}.tar.bz2'.format(os.environ['RTEMS'])
print('Downloading RTEMS {0} cross compiler: {1}' print('Downloading RTEMS {0} cross compiler: {1}'
@@ -858,7 +902,10 @@ USR_CXXFLAGS += {0}'''.format(os.environ['USR_CXXFLAGS'])
'https://github.com/mdavidsaver/rsb/releases/download/20171203-{0}/{1}' 'https://github.com/mdavidsaver/rsb/releases/download/20171203-{0}/{1}'
.format(os.environ['RTEMS'], tar_name)], .format(os.environ['RTEMS'], tar_name)],
cwd=toolsdir) cwd=toolsdir)
sp.check_call(['tar', '-C', '/', '-xmj', '-f', os.path.join(toolsdir, tar_name)]) sudo_prefix = []
if ci['service'] == 'github-actions':
sudo_prefix = ['sudo']
sp.check_call(sudo_prefix + ['tar', '-C', '/', '-xmj', '-f', os.path.join(toolsdir, tar_name)])
os.remove(os.path.join(toolsdir, tar_name)) os.remove(os.path.join(toolsdir, tar_name))
setup_for_build(args) setup_for_build(args)

57
github-actions/README.md Normal file
View File

@@ -0,0 +1,57 @@
# GitHub Actions Scripts for EPICS Modules
## Features
- 20 parallel runners on Linux/Windows (5 runners on MacOS)
- Ubuntu 16/18/20, MacOS 10.15, Windows Server 2016/2019
- Compile natively on Linux (gcc, clang)
- Compile natively on MacOS (clang)
- Compile natively on Windows (gcc/MinGW, Visual Studio 2017 & 2019)
- Cross-compile for Windows 32bit and 64bit using MinGW and WINE
- Cross-compile for RTEMS 4.9 and 4.10 (Base >= 3.15)
- Caching not supported yet.
## How to Use these Scripts
1. Add the ci-scripts respository as a Git Submodule
(see [README](../README.md) one level above).
2. Add settings files defining which dependencies in which versions
you want to build against
(see [README](../README.md) one level above).
3. Create a GitHub Actions configuration by copying one of the workflow
examples into the directory `.github/workflows` of your module.
```bash
$ mkdir -p .github/workflows
$ cp .ci/github-actions/ci-scripts-build.yml.example-full .github/workflows/ci-scripts-build.yml
```
4. Edit the workflow configuration to include the build jobs you want
GitHub Actions to run.
Build jobs are specified in the `jobs: <job-name>: strategy:`
declaration. The `matrix:` element specifies the axes as configuration
parameters with their lists of values,
`env:` (on the build level) controls the setting of environment variables
(which can be matrix parameters).
The `runs-on:` setting specifies the image (operating system) of the
runner.
The `name:` is what shows up in the web interface for the workflow,
builds and jobs, and the elements under `steps:` describe the actions
executed for each job of the matrix.
Please check the comments in the examples for more hints, and the
[GitHub Actions documentation](https://help.github.com/en/actions)
for a lot more options and details.
5. Push your changes and click on the `Actions` tab of your GitHub repository
page to see your build results.
## Caches
GitHub Actions provides caching of dependencies.
However, since their cache restore and create algorithm is fundamentally
different from those used by Travis and AppVeyor, this will require some
more changes in ci-scripts to work. Be patient.

View File

@@ -0,0 +1,155 @@
# .github/workflows/ci-scripts-build.yml for use with EPICS Base ci-scripts
# (see: https://github.com/epics-base/ci-scripts)
# This is YAML - indentation levels are crucial
# Set the 'name:' properties to values that work for you (MYMODULE)
name: MYMODULE ci-scripts build
# Trigger on pushes and PRs to any branch
on: [push, pull_request]
env:
SETUP_PATH: .ci-local:.ci
SET: test01
CMP: gcc
# For the sequencer on Linux/Windows/MacOS
APT: re2c
CHOCO: re2c
BREW: re2c
jobs:
build-linux:
name: ${{ matrix.cmp }} / ${{ matrix.configuration }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
# Set environment variables from matrix parameters
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-16.04]
cmp: [gcc, clang]
configuration: [default, static, debug, static-debug]
steps:
- uses: actions/checkout@v2
- name: Prepare and compile dependencies
run: python cue.py prepare
- name: Build main module
run: python cue.py build
- name: Run main module tests
run: python cue.py test
- name: Collect and show test results
run: python cue.py test-results
build-macos:
name: ${{ matrix.cmp }} / ${{ matrix.configuration }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
# Set environment variables from matrix parameters
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
strategy:
fail-fast: false
matrix:
os: [macos-10.15]
cmp: [clang]
# No static builds on MacOS
configuration: [default, debug]
steps:
- uses: actions/checkout@v2
- name: Prepare and compile dependencies
run: python cue.py prepare
- name: Build main module
run: python cue.py build
- name: Run main module tests
run: python cue.py test
- name: Collect and show test results
run: python cue.py test-results
build-windows:
name: ${{ matrix.cmp }} / ${{ matrix.configuration }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
strategy:
fail-fast: false
matrix:
os: [windows-2019, windows-2016]
cmp: [gcc, vs2019, vs2017]
configuration: [default, static, debug, static-debug]
# Available: vs2017/windows-2016 and vs2019/windows-2019
exclude:
- os: windows-2019
cmp: vs2017
- os: windows-2016
cmp: vs2019
steps:
- uses: actions/checkout@v2
- name: Prepare and compile dependencies
run: python cue.py prepare
- name: Build main module
run: python cue.py build
- name: Run main module tests
run: python cue.py test
- name: Collect and show test results
run: python cue.py test-results
# Same setup and toolchain as on Travis.
# Needs Base >= 3.15 to compile, EPICS 7 to also run the tests on qemu
build-rtems:
name: RTEMS${{ matrix.rtems }} / ${{ matrix.configuration }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
RTEMS: ${{ matrix.rtems }}
APT: re2c g++-mingw-w64-i686 g++-mingw-w64-x86-64 qemu-system-x86
strategy:
fail-fast: false
matrix:
os: [ubuntu-18.04]
cmp: [gcc]
configuration: [default, static, debug, static-debug]
rtems: ["4.9", "4.10"]
steps:
- uses: actions/checkout@v2
- name: Prepare and compile dependencies
run: python cue.py prepare
- name: Build main module
run: python cue.py build
- name: Run main module tests
run: python cue.py test
- name: Collect and show test results
run: python cue.py test-results
# The WINE cross builds are of somewhat limited use,
# as there are native gcc/MinGW builds available on GitHub Actions
build-wine:
name: WINE${{ matrix.wine }} / ${{ matrix.configuration }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
WINE: ${{ matrix.wine }}
APT: re2c g++-mingw-w64-i686 g++-mingw-w64-x86-64
strategy:
fail-fast: false
matrix:
os: [ubuntu-18.04]
cmp: [gcc]
configuration: [default, static, debug, static-debug]
wine: [32, 64]
steps:
- uses: actions/checkout@v2
- name: Prepare and compile dependencies
run: python cue.py prepare
- name: Build main module
run: python cue.py build
- name: Run main module tests
run: python cue.py test
- name: Collect and show test results
run: python cue.py test-results

View File

@@ -0,0 +1,43 @@
# .github/workflows/ci-scripts-build.yml for use with EPICS Base ci-scripts
# (see: https://github.com/epics-base/ci-scripts)
# This is YAML - indentation levels are crucial
# Set the 'name:' properties to values that work for you
name: MYMODULE ci-scripts build
# Trigger on pushes and PRs to any branch
on: [push, pull_request]
env:
SETUP_PATH: .ci-local:.ci
SET: test01
CMP: gcc
jobs:
build-linux:
name: ${{ matrix.base }} / ${{ matrix.cmp }} / ${{ matrix.configuration }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
# Set environment variables from matrix parameters
env:
CMP: ${{ matrix.cmp }}
BCFG: ${{ matrix.configuration }}
BASE: ${{ matrix.base }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, ubuntu-18.04]
cmp: [gcc]
configuration: [default, static]
base: ["7.0", "3.15"]
steps:
- uses: actions/checkout@v2
- name: Prepare and compile dependencies
run: python cue.py prepare
- name: Build main module
run: python cue.py build
- name: Run main module tests
run: python cue.py test
- name: Collect and show test results
run: python cue.py test-results