Skip to content

Build and check Erlang/OTP #342

Build and check Erlang/OTP

Build and check Erlang/OTP #342

Workflow file for this run

##
## This workflow handles testing of pull requests and pushes.
## It also publishes some packages to any new Erlang/OTP release
##
## To speed this up it would be nice if one could share docker
## images inbetween different jobs, but at the moment this is
## not possible so we need to rebuild all of Erlang/OTP multiple
## times.
##
## Now that we have migrated to ghcr.io we use the
## built-in caching mechanisms of docker/build-push-action@v2.
## However as things are now we use docker directly to make things
## work due to historical reasons.
##
name: Build and check Erlang/OTP
on:
push:
pull_request:
schedule:
- cron: 0 1 * * *
env:
## Equivalent to github.event_name == 'pull_request' ? github.base_ref : github.ref_name
BASE_BRANCH: ${{ github.event_name == 'pull_request' && github.base_ref || github.ref_name }}
jobs:
pack:
name: Build Erlang/OTP (64-bit)
runs-on: ubuntu-latest
outputs:
BASE_BUILD: ${{ steps.base-build.outputs.BASE_BUILD }}
changes: ${{ steps.changes.outputs.changes }}
all: ${{ steps.apps.outputs.all }}
steps:
- uses: actions/[email protected]
- uses: ./.github/actions/build-base-image
with:
BASE_BRANCH: ${{ env.BASE_BRANCH }}
BUILD_IMAGE: false
- name: Get applications
id: apps
run: |
.github/scripts/path-filters.sh > .github/scripts/path-filters.yaml
## Print path-filters for debug purposes
cat .github/scripts/path-filters.yaml
ALL_APPS=$(grep '^[a-z_]*:' .github/scripts/path-filters.yaml | sed 's/:.*$//')
ALL_APPS=$(jq -n --arg inarr "${ALL_APPS}" '$inarr | split("\n")' | tr '\n' ' ')
echo "all=${ALL_APPS}" >> $GITHUB_OUTPUT
- uses: dorny/[email protected]
id: app-changes
with:
filters: .github/scripts/path-filters.yaml
- name: Override changes
id: changes
env:
ALL_APPS: ${{ steps.apps.outputs.all }}
CHANGED_APPS: ${{ steps.app-changes.outputs.changes }}
run: |
if ${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'full-build-and-check') }} || ${{ github.event_name == 'schedule' }}; then
echo "changes=${ALL_APPS}" >> "$GITHUB_OUTPUT"
else
echo "changes=${CHANGED_APPS}" >> "$GITHUB_OUTPUT"
fi
- name: Create initial pre-release tar
run: .github/scripts/init-pre-release.sh otp_archive.tar.gz
- name: Upload source tar archive
uses: actions/[email protected]
with:
name: otp_git_archive
path: otp_archive.tar.gz
- name: Cache pre-built src
uses: actions/[email protected]
with:
path: otp_src.tar.gz
key: prebuilt-src-${{ github.ref_name }}-${{ github.sha }}
restore-keys: |
prebuilt-src-${{ github.base_ref }}-${{ github.event.pull_request.base.sha }}
- name: Cache pre-built binaries
uses: actions/[email protected]
with:
path: otp_cache.tar.gz
key: prebuilt-cache-64-bit-${{ github.ref_name }}-${{ github.sha }}
restore-keys: |
prebuilt-cache-64-bit-${{ github.base_ref }}-${{ github.event.pull_request.base.sha }}
- uses: dorny/[email protected]
id: cache
with:
filters: |
no-cache:
- '.github/**'
deleted:
- deleted: '**'
bootstrap:
- 'bootstrap/**'
configure:
- '**.ac'
- '**.in'
list-files: shell
- name: Restore from cache
env:
NO_CACHE: ${{ steps.cache.outputs.no-cache || steps.cache.outputs.deleted_count > 20 }}
BOOTSTRAP: ${{ steps.cache.outputs.bootstrap }}
CONFIGURE: ${{ steps.cache.outputs.configure }}
EVENT: ${{ github.event_name }}
DELETED: ${{ steps.cache.outputs.deleted_files }}
run: |
.github/scripts/restore-from-prebuilt.sh "`pwd`" \
"`pwd`/.github/otp.tar.gz" \
"`pwd`/otp_archive.tar.gz"
- name: Upload restored cache
uses: actions/[email protected]
if: runner.debug == 1
with:
name: restored-cache
path: .github/otp.tar.gz
- name: Build image
run: |
docker build --tag otp \
--build-arg MAKEFLAGS=-j$(($(nproc) + 2)) \
--file ".github/dockerfiles/Dockerfile.64-bit" \
.github/
- name: Build pre-built tar archives
run: |
## Do a little dance to add new files to the cache
gunzip otp_src.tar.gz
gunzip otp_archive.tar.gz
tar -f otp_src_archive.tar --concatenate otp_archive.tar otp_src.tar
## The resulting otp_src.tar.gz needs to be opened with -i, which build-otp-tar does
gzip otp_src_archive.tar
docker run -v $PWD:/github --entrypoint "" otp \
scripts/build-otp-tar -o /github/otp_clean_src.tar.gz /github/otp_src.tar.gz -b /buildroot/otp/ /github/otp_src_archive.tar.gz
- name: Build cache
run: |
if [ -f otp_cache.tar.gz ]; then
gunzip otp_cache.tar.gz
else
docker run -v $PWD:/github --entrypoint "" otp \
bash -c 'cp ../otp_cache.tar /github/'
fi
docker run -v $PWD:/github --entrypoint "" otp \
bash -c 'set -x; C_APPS=$(ls -d ./lib/*/c_src); find Makefile ./make ./erts ./bin/`erts/autoconf/config.guess` ./lib/erl_interface ./lib/jinterface ${C_APPS} `echo "${C_APPS}" | sed -e 's:c_src$:priv:'` -type f -newer README.md \! -name "*.beam" \! -path "*/doc/*" | xargs tar --transform "s:^./:otp/:" -uvf /github/otp_cache.tar'
gzip otp_cache.tar
- name: Upload concatenated archive
uses: actions/[email protected]
if: runner.debug == 1
with:
name: otp_src_archive
path: otp_src_archive.tar.gz
- name: Upload pre-built tar archives
uses: actions/[email protected]
with:
name: otp_prebuilt
path: |
otp_src.tar.gz
otp_cache.tar.gz
build-macos:
name: Build Erlang/OTP (macOS)
runs-on: macos-12
needs: pack
env:
WXWIDGETS_VERSION: 3.1.5
steps:
- uses: actions/[email protected]
- name: Download source archive
uses: actions/[email protected]
with:
name: otp_prebuilt
- name: Cache wxWidgets
id: wxwidgets-cache
uses: actions/[email protected]
with:
path: wxWidgets
key: wxWidgets-${{ env.WXWIDGETS_VERSION }}-${{ runner.os }}-12
- name: Compile wxWidgets
if: steps.wxwidgets-cache.outputs.cache-hit != 'true'
run: .github/scripts/build-macos-wxwidgets.sh
- name: Compile Erlang
run: |
tar -xzf ./otp_src.tar.gz
export PATH=$PWD/wxWidgets/release/bin:$PATH
cd otp
$GITHUB_WORKSPACE/.github/scripts/build-macos.sh build_docs --disable-dynamic-ssl-lib
tar -czf otp_macos_$(cat OTP_VERSION)_x86-64.tar.gz -C release .
- name: Test Erlang
run: |
cd otp/release
./Install -sasl $PWD
./bin/erl -noshell -eval 'io:format("~s", [erlang:system_info(system_version)]), halt().'
./bin/erl -noshell -eval 'ok = crypto:start(), io:format("crypto ok~n"), halt().'
./bin/erl -noshell -eval '{wx_ref,_,_,_} = wx:new(), io:format("wx ok~n"), halt().'
- name: Upload tarball
uses: actions/[email protected]
with:
name: otp_prebuilt_macos_x86-64
path: otp/otp_macos_*_x86-64.tar.gz
build-ios:
env:
RELEASE_LIBBEAM: yes
TARGET_ARCH: aarch64-apple-ios
name: Build Erlang/OTP (iOS)
runs-on: macos-12
needs: pack
steps:
- uses: actions/[email protected]
- name: Download source archive
uses: actions/[email protected]
with:
name: otp_prebuilt
- name: Compile Erlang
run: |
tar -xzf ./otp_src.tar.gz
cd otp
$GITHUB_WORKSPACE/.github/scripts/build-macos.sh --xcomp-conf=./xcomp/erl-xcomp-arm64-ios.conf --without-ssl
- name: Package .xcframework
run: |
cd otp
export BUILD_ARCH=`./erts/autoconf/config.guess`
export LIBS=`find . -not -path "*${BUILD_ARCH}*" -path "*${TARGET_ARCH}*" -not -name "*_st.a" -not -name "*_r.a" -name "*.a" | awk '{ "basename " $1 | getline name; names[name] = $1 } END { for (n in names) { print names[n] }}'`
libtool -static -o liberlang.a $LIBS
xcodebuild -create-xcframework -output ./liberlang.xcframework -library liberlang.a
- name: Upload framework
uses: actions/[email protected]
with:
name: ios_framework_${{ env.TARGET_ARCH }}
path: otp/liberlang.xcframework
build-windows:
defaults:
run:
shell: wsl-bash {0}
env:
WXWIDGETS_VERSION: 3.1.4
name: Build Erlang/OTP (Windows)
runs-on: windows-2022
needs: pack
steps:
- uses: Vampire/[email protected]
with:
distribution: Ubuntu-18.04
- name: Install WSL dependencies
run: apt update && apt install -y g++-mingw-w64 gcc-mingw-w64 make autoconf unzip
- name: Install openssl
shell: cmd
run: |
choco install openssl
IF EXIST "c:\\Program Files\\OpenSSL-Win64" (move "c:\\Program Files\\OpenSSL-Win64" "c:\\OpenSSL-Win64") ELSE (move "c:\\Program Files\\OpenSSL" "c:\\OpenSSL-Win64")
- name: Cache wxWidgets
uses: actions/[email protected]
with:
path: wxWidgets
key: wxWidgets-${{ env.WXWIDGETS_VERSION }}-${{ runner.os }}
# actions/cache on Windows sometimes does not set cache-hit even though there was one. Setting it manually.
- name: Set wxWidgets cache
id: wxwidgets-cache
env:
WSLENV: GITHUB_OUTPUT/p
run: |
if [ -d wxWidgets ]; then
echo "cache-hit=true" >> $GITHUB_OUTPUT
else
echo "cache-hit=false" >> $GITHUB_OUTPUT
fi
- name: Download wxWidgets
if: steps.wxwidgets-cache.outputs.cache-hit != 'true'
run: |
wget https://github.com/wxWidgets/wxWidgets/releases/download/v${{ env.WXWIDGETS_VERSION }}/wxWidgets-${{ env.WXWIDGETS_VERSION }}.zip
unzip wxWidgets-${{ env.WXWIDGETS_VERSION }}.zip -d wxWidgets
sed -i -r -e 's/wxUSE_POSTSCRIPT +0/wxUSE_POSTSCRIPT 1/' wxWidgets/include/wx/msw/setup.h
sed -i -r -e 's/wxUSE_WEBVIEW_EDGE +0/wxUSE_WEBVIEW_EDGE 1/' wxWidgets/include/wx/msw/setup.h
- name: Install WebView2
if: steps.wxwidgets-cache.outputs.cache-hit != 'true'
shell: cmd
run: |
cd wxWidgets\\3rdparty
nuget install Microsoft.Web.WebView2 -Version 1.0.705.50 -Source https://api.nuget.org/v3/index.json
rename Microsoft.Web.WebView2.1.0.705.50 webview2
- name: Build wxWidgets
if: steps.wxwidgets-cache.outputs.cache-hit != 'true'
shell: cmd
run: |
cd wxWidgets\\build\\msw
call "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\Auxiliary\\Build\\vcvars64.bat"
nmake TARGET_CPU=amd64 BUILD=release SHARED=0 DIR_SUFFIX_CPU= -f makefile.vc
- name: Download source archive
uses: actions/[email protected]
with:
name: otp_prebuilt
- name: Compile Erlang
run: |
mkdir -p /mnt/c/opt/local64/pgm/
cp -R wxWidgets /mnt/c/opt/local64/pgm/wxWidgets-${{ env.WXWIDGETS_VERSION }}
tar -xzf ./otp_src.tar.gz
cd otp
export ERL_TOP=`pwd`
export MAKEFLAGS=-j$(($(nproc) + 2))
export ERLC_USE_SERVER=true
export ERTS_SKIP_DEPEND=true
eval `./otp_build env_win32 x64`
./otp_build configure
if cat erts/CONF_INFO ||
grep -v "Static linking with OpenSSL 3.0" lib/*/CONF_INFO ||
cat lib/*/SKIP ||
cat lib/SKIP-APPLICATIONS; then
exit 1
fi
./otp_build boot -a
./otp_build release -a
cp /mnt/c/opt/local64/pgm/wxWidgets-${{ env.WXWIDGETS_VERSION }}/3rdparty/webview2/runtimes/win-x64/native/WebView2Loader.dll $ERL_TOP/release/win32/erts-*/bin/
./otp_build installer_win32
- name: Upload installer
uses: actions/[email protected]
with:
name: otp_win32_installer
path: otp/release/win32/otp*.exe
build-flavors:
name: Build Erlang/OTP (Types and Flavors)
runs-on: ubuntu-latest
needs: pack
if: contains(needs.pack.outputs.changes, 'emulator')
steps:
- uses: actions/[email protected]
- uses: ./.github/actions/build-base-image
with:
BASE_BRANCH: ${{ env.BASE_BRANCH }}
- name: Build Erlang/OTP flavors and types
run: |
TYPES="opt debug lcnt"
FLAVORS="emu jit"
for TYPE in ${TYPES}; do
for FLAVOR in ${FLAVORS}; do
echo "::group::{TYPE=$TYPE FLAVOR=$FLAVOR}"
docker run otp "make TYPE=$TYPE FLAVOR=$FLAVOR"
echo "::endgroup::"
done
done
build:
name: Build Erlang/OTP
runs-on: ubuntu-latest
needs: pack
strategy:
matrix:
type: [32-bit,cross-compile,clang]
fail-fast: false
steps:
- uses: actions/[email protected]
- uses: ./.github/actions/build-base-image
with:
BASE_BRANCH: ${{ env.BASE_BRANCH }}
TYPE: ${{ matrix.type }}
documentation:
name: Build and check documentation
runs-on: ubuntu-latest
needs: pack
steps:
- uses: actions/[email protected]
- uses: ./.github/actions/build-base-image
with:
BASE_BRANCH: ${{ env.BASE_BRANCH }}
## Build all the documentation
- name: Build documentation
run: |
docker build -t otp - <<EOF
FROM otp
RUN make release docs release_docs && sudo make install-docs
EOF
- name: Release docs to publish
run: |
docker run -v $PWD/:/github otp \
"make release_docs DOC_TARGETS='man html pdf' RELEASE_ROOT=/github/docs"
sudo chown -R `whoami` docs
cd docs
tar czf ../otp_doc_man.tar.gz man
rm -rf man
tar czf ../otp_doc_html.tar.gz *
- name: Upload html documentation archive
uses: actions/[email protected]
with:
name: otp_doc_html
path: otp_doc_html.tar.gz
- name: Upload man documentation archive
uses: actions/[email protected]
with:
name: otp_doc_man
path: otp_doc_man.tar.gz
## Documentation checks
- name: Run xmllint
run: docker run otp "make xmllint"
- name: Run html link check
run: docker run -v $PWD/:/github otp "/github/scripts/otp_html_check /github/docs doc/index.html"
static:
name: Run static analysis
runs-on: ubuntu-latest
needs: pack
steps:
- uses: actions/[email protected]
- uses: ./.github/actions/build-base-image
with:
BASE_BRANCH: ${{ env.BASE_BRANCH }}
- name: Install clang-format
run: |
docker build -t otp - <<EOF
FROM otp
RUN sudo apt-get install -y clang-format
EOF
## Check formatting of cpp code
- name: Check format
run: docker run otp "make format-check"
## Run dialyzer
- name: Run dialyzer
run: docker run -v $PWD/:/github otp '/github/scripts/run-dialyzer'
test:
name: Test Erlang/OTP
runs-on: ubuntu-latest
needs: pack
if: needs.pack.outputs.changes != '[]'
strategy:
matrix:
# type: ${{ fromJson(needs.pack.outputs.all) }}
type: ${{ fromJson(needs.pack.outputs.changes) }}
# type: ["os_mon","sasl"]
fail-fast: false
steps:
- uses: actions/[email protected]
- uses: ./.github/actions/build-base-image
with:
BASE_BRANCH: ${{ env.BASE_BRANCH }}
- name: Run tests
id: run-tests
run: |
set -x
mkdir $PWD/make_test_dir
APP="${{ matrix.type }}"
## Need to specialize for epmd, emulator and debug
case "${APP}" in
emulator) DIR=erts/emulator/ ;;
epmd) DIR=erts/epmd ;;
debug) DIR=lib/os_mon; APP=os_mon; TYPE=debug ;;
*) DIR=lib/${{ matrix.type }} ;;
esac
sudo service apport stop
sudo bash -c "echo 'core.%p' > /proc/sys/kernel/core_pattern"
docker run --ulimit core=-1 --ulimit nofile=5000:5000 --pids-limit 512 \
-e CTRUN_TIMEOUT=90 -e SPEC_POSTFIX=gh \
-e TEST_NEEDS_RELEASE=true -e "RELEASE_ROOT=/buildroot/otp/Erlang ∅⊤℞" \
-e EXTRA_ARGS="-ct_hooks cth_surefire [{path,\"/buildroot/otp/$DIR/make_test_dir/${{ matrix.type }}_junit.xml\"}]" \
-v "$PWD/make_test_dir:/buildroot/otp/$DIR/make_test_dir" \
-v "$PWD/scripts:/buildroot/otp/scripts" \
otp "make TYPE=${TYPE} && make ${APP}_test TYPE=${TYPE}"
## Rename os_mon to debug for debug build
if [ "$APP" != "${{ matrix.type }}" ]; then
mv make_test_dir/${APP}_test "make_test_dir/${{ matrix.type }}_test"
fi
- name: Cleanup tests
if: always()
run: |
rm -rf make_test_dir/otp || true
sudo bash -c "chown -R `whoami` make_test_dir && chmod -R +r make_test_dir"
tar czf ${{ matrix.type }}_test_results.tar.gz make_test_dir
- name: Upload test results
uses: actions/[email protected]
if: always()
with:
name: ${{ matrix.type }}_test_results
path: ${{ matrix.type }}_test_results.tar.gz
system-test:
name: Test Erlang/OTP (system)
runs-on: ubuntu-latest
if: always() # Run even if the need has failed
needs: test
steps:
- uses: actions/[email protected]
- uses: ./.github/actions/build-base-image
with:
BASE_BRANCH: ${{ env.BASE_BRANCH }}
- name: Download test results
uses: actions/[email protected]
- name: Merge test results
run: |
shopt -s nullglob
mkdir -p make_test_dir
for file in *_test_results/*.tar.gz; do
tar xzf $file
done
docker run -v $PWD/make_test_dir:/buildroot/otp/erts/make_test_dir otp \
"ct_run -refresh_logs /buildroot/otp/erts/make_test_dir"
- name: Run system tests
run: |
docker run --ulimit core=-1 --ulimit nofile=5000:5000 --pids-limit 512 \
-e CTRUN_TIMEOUT=90 -e SPEC_POSTFIX=gh \
-e EXTRA_ARGS="-ct_hooks cth_surefire [{path,\"/buildroot/otp/erts/make_test_dir/system_junit.xml\"}]" \
-e OTP_DAILY_BUILD_TOP_DIR=/buildroot/otp/erts/make_test_dir \
-v $PWD/make_test_dir:/buildroot/otp/erts/make_test_dir otp \
"make system_test"
- name: Cleanup tests
if: always()
run: |
rm -rf make_test_dir/otp || true
tar czf test_results.tar.gz make_test_dir
# Translate file="/buildroot/otp/lib/os_mon/make_test_dir/os_mon_test/cpu_sup_SUITE.erl"
# to file="lib/os_mon/test/cpu_sup_SUITE.erl"
sed -i -e 's:file="/buildroot/otp/:file=":g' \
-e 's:\(file="[^/]*/[^/]*/\)make_test_dir/[^/]*:\1test:g' \
-e 's:\(file="erts/\)make_test_dir/[^/]*:\1test:g' \
make_test_dir/*_junit.xml
- name: Upload test results
uses: actions/[email protected]
if: always()
with:
name: test_results
path: test_results.tar.gz
- name: Upload Test Results
if: always()
uses: actions/[email protected]
with:
name: Unit Test Results
path: |
make_test_dir/*_junit.xml
## If this is a tag that has been pushed we do some release work
release:
name: Release Erlang/OTP
runs-on: ubuntu-latest
needs: documentation
if: startsWith(github.ref, 'refs/tags/') && github.repository == 'erlang/otp'
steps:
## This step outputs the tag name and whether the tag is a release or patch
## (all releases have only two version identifiers, while patches have three
## or more)
- name: Get Tag Name
id: tag
run: |
TAG=${GITHUB_REF#refs/tags/}
VSN=${TAG#OTP-}
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "vsn=${VSN}" >> $GITHUB_OUTPUT
- uses: actions/[email protected]
## Publish the pre-built archive and docs
- name: Download source archive
uses: actions/[email protected]
with:
name: otp_prebuilt
- name: Download html docs
uses: actions/[email protected]
with:
name: otp_doc_html
- name: Download man docs
uses: actions/[email protected]
with:
name: otp_doc_man
## We add the correct version name into the file names
## and create the hash files for all assets
- name: Create pre-build and doc archives
run: .github/scripts/create-artifacts.sh artifacts ${{ steps.tag.outputs.tag }}
## Create hash files
- name: Create pre-build and doc archives
run: |
shopt -s nullglob
cd artifacts
FILES=$(ls {*.tar.gz,*.txt})
md5sum $FILES > MD5.txt
sha256sum $FILES > SHA256.txt
- name: Upload pre-built and doc tar archives
uses: softprops/action-gh-release@v1
with:
name: OTP ${{ steps.tag.outputs.vsn }}
files: |
artifacts/*.tar.gz
artifacts/*.txt
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy on erlang.org
env:
GITHUB_TOKEN: ${{ secrets.TRIGGER_ERLANG_ORG_BUILD }}
run: |
curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/erlang/erlang-org/actions/workflows/update-gh-cache.yaml/dispatches" -d '{"ref":"master"}'
event_file:
name: "Event File"
runs-on: ubuntu-latest
steps:
- name: Upload
uses: actions/[email protected]
with:
name: Event File
path: ${{ github.event_path }}