diff --git a/appveyor-ci.yml b/appveyor-ci.yml new file mode 100644 index 000000000..4cc36adb8 --- /dev/null +++ b/appveyor-ci.yml @@ -0,0 +1,44 @@ +version: 1.0.{build} +image: + - Visual Studio 2017 + - Ubuntu +environment: + matrix: + - ARCH: amd64 + - ARCH: arm + - ARCH: arm64 + - ARCH: ppc64le + - ARCH: s390x + DOCKER_USER: + secure: JapmC7j5F0mY3j/MVzU+Cw== + DOCKER_PASS: + secure: QGlCLNWzPD0HL8ipkohVic45/yU3bVOdjn0IiV6NnSQ= +matrix: + exclude: + - image: Visual Studio 2017 + ARCH: arm + - image: Visual Studio 2017 + ARCH: arm64 + - image: Visual Studio 2017 + ARCH: ppc64le + - image: Visual Studio 2017 + ARCH: s390x +branches: + except: + - master +stack: + - node 9, go 1.10 +install: + - yarn install + - npm install -g rebase-docker-image +init: + - sh: export IMAGE=linux + - cmd: SET IMAGE=windows + - ps: >- + if (!(Test-Path ~/.docker)) { mkdir ~/.docker }; + Set-Content -Value '{ "experimental": "enabled" }' -Path ~/.docker/config.json -Encoding Ascii +build_script: + - sh: yarn grunt release:$IMAGE:$ARCH + - cmd: yarn grunt release:%IMAGE%:%ARCH% + - sh: sudo bash build/ci-linux.sh $IMAGE $ARCH $DOCKER_USER $DOCKER_PASS $APPVEYOR_REPO_BRANCH $APPVEYOR_PULL_REQUEST_NUMBER + - cmd: powershell -Command "& .\\build\\ci-windows.ps1" \ No newline at end of file diff --git a/appveyor-release.yml b/appveyor-release.yml new file mode 100644 index 000000000..348897690 --- /dev/null +++ b/appveyor-release.yml @@ -0,0 +1,61 @@ +version: 1.0.{build} +image: + - Visual Studio 2017 + - Ubuntu +environment: + matrix: + - ARCH: amd64 + - ARCH: arm + - ARCH: arm64 + - ARCH: ppc64le + - ARCH: s390x + DOCKER_USER: + secure: JapmC7j5F0mY3j/MVzU+Cw== + DOCKER_PASS: + secure: QGlCLNWzPD0HL8ipkohVic45/yU3bVOdjn0IiV6NnSQ= + PORTAINER_VERSION: "1.19.2" +matrix: + exclude: + - image: Visual Studio 2017 + ARCH: arm + - image: Visual Studio 2017 + ARCH: arm64 + - image: Visual Studio 2017 + ARCH: ppc64le + - image: Visual Studio 2017 + ARCH: s390x +branches: + only: + - master +stack: node 9, go 1.10 +artifacts: + - path: 'portainer-$(PORTAINER_VERSION)-$(IMAGE)-$(ARCH).tar.gz' + type: file + - path: 'portainer-$(PORTAINER_VERSION)-$(IMAGE)-$(ARCH)-checksum.txt' + type: file +install: + - yarn install + - npm install -g rebase-docker-image +init: + - sh: export IMAGE=linux + - cmd: SET IMAGE=windows + - ps: >- + if (!(Test-Path ~/.docker)) { mkdir ~/.docker } + Set-Content -Value '{ "experimental": "enabled" }' -Path ~/.docker/config.json -Encoding Ascii +build_script: + - sh: yarn grunt release:$IMAGE:$ARCH + - cmd: yarn grunt release:%IMAGE%:%ARCH% + - sh: sudo bash build/release-linux.sh $IMAGE $ARCH $PORTAINER_VERSION $DOCKER_USER $DOCKER_PASS + - cmd: powershell -Command "& .\\build\\release-windows.ps1" +test: off +deploy: + release: Release $(PORTAINER_VERSION) + description: '' + provider: GitHub + auth_token: + secure: BRYVGj94QlFBCMoO8yhSu+AGqKNV1+03LJEFrNUTRzo5erXfUHUIi/rgztnxfSGW + artifact: /portainer-$(PORTAINER_VERSION)-$(IMAGE)-$(ARCH).*/ + draft: true + prerelease: false + on: + branch: master diff --git a/build/build_binary.ps1 b/build/build_binary.ps1 new file mode 100644 index 000000000..5d486c1f4 --- /dev/null +++ b/build/build_binary.ps1 @@ -0,0 +1,24 @@ +param ( + [string]$platform, + [string]$arch +) + +$ErrorActionPreference = "Stop"; + +$binary = "portainer.exe" +$project_path = (Get-ITEM -Path env:APPVEYOR_BUILD_FOLDER).Value + +Set-Item env:GOPATH "$project_path\api" + +New-Item -Name dist -Path "$project_path" -ItemType Directory | Out-Null +New-Item -Name portainer -Path "$project_path\api\src\github.com\" -ItemType Directory | Out-Null + +Copy-Item -Path "$project_path\api" -Destination "$project_path\api\src\github.com\portainer" -Recurse -Force -ErrorAction:SilentlyContinue +Rename-Item -Path "$project_path\api\src\github.com\portainer\api" -NewName "portainer" -ErrorAction:SilentlyContinue + +Set-Location -Path "$project_path\api\cmd\portainer" + +C:\go\bin\go.exe get -t -d -v ./... +C:\go\bin\go.exe build -v + +Move-Item -Path "$project_path\api\cmd\portainer\$($binary)" -Destination "$project_path\dist" diff --git a/build/build_binary.sh b/build/build_binary.sh new file mode 100755 index 000000000..ae57b007b --- /dev/null +++ b/build/build_binary.sh @@ -0,0 +1,14 @@ +export GOPATH="$APPVEYOR_BUILD_FOLDER/api" +binary="portainer" + +mkdir -p dist +mkdir -p api/src/github.com/portainer/ + +cp -R api/ api/src/github.com/portainer/portainer/ + +cd 'api/cmd/portainer' + +go get -t -d -v ./... +GOOS=$1 GOARCH=$2 CGO_ENABLED=0 go build -a --installsuffix cgo --ldflags '-s' + +mv "$APPVEYOR_BUILD_FOLDER/api/cmd/portainer/$binary" "$APPVEYOR_BUILD_FOLDER/dist/portainer" diff --git a/build/build_in_container.sh b/build/build_in_container.sh deleted file mode 100755 index a827bddfd..000000000 --- a/build/build_in_container.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env sh - -binary="portainer-$1-$2" - -mkdir -p dist - -docker run --rm -tv "$(pwd)/api:/src" -e BUILD_GOOS="$1" -e BUILD_GOARCH="$2" portainer/golang-builder:cross-platform /src/cmd/portainer - -mv "api/cmd/portainer/$binary" dist/ -#sha256sum "dist/$binary" > portainer-checksum.txt diff --git a/build/ci-linux.sh b/build/ci-linux.sh new file mode 100644 index 000000000..1308d568d --- /dev/null +++ b/build/ci-linux.sh @@ -0,0 +1,28 @@ +IMAGE="$1" +ARCH="$2" +DOCKER_USER="$3" +DOCKER_PASS="$4" +APPVEYOR_REPO_BRANCH="$5" +APPVEYOR_PULL_REQUEST_NUMBER="$6" + +if [ "${APPVEYOR_PULL_REQUEST_NUMBER}" ]; then + tag="pr${APPVEYOR_PULL_REQUEST_NUMBER}-$IMAGE-$ARCH" + manifest="pr${APPVEYOR_PULL_REQUEST_NUMBER}" +else + tag="${APPVEYOR_REPO_BRANCH}-$IMAGE-$ARCH" + manifest="${APPVEYOR_REPO_BRANCH}" +fi + +docker build -t "portainer/portainer:$tag" -f build/linux/Dockerfile . +docker login -u "${DOCKER_USER}" -p "${DOCKER_PASS}" +docker push "portainer/portainer:$tag" + +if [ "${2}" == 'amd64' ] ; then + docker -D manifest create "portainer/portainer:$manifest" \ + "portainer/portainer:$manifest-linux-amd64" \ + "portainer/portainer:$manifest-windows-amd64" \ + "portainer/portainer:$manifest-windows1709-amd64" \ + "portainer/portainer:$manifest-windows1803-amd64" + + docker manifest push "portainer/portainer:$manifest" +fi diff --git a/build/ci-windows.ps1 b/build/ci-windows.ps1 new file mode 100644 index 000000000..73a8720b2 --- /dev/null +++ b/build/ci-windows.ps1 @@ -0,0 +1,36 @@ +$ErrorActionPreference = "Stop"; + +$pull_request_number = $ENV:APPVEYOR_PULL_REQUEST_NUMBER +$branch_name = $ENV:APPVEYOR_REPO_BRANCH +$os = (Get-Item ENV:IMAGE).Value +$arch = (Get-Item ENV:ARCH).Value + +if ($pull_request_number) { + $tag = "pr$($pull_request_number)-$($os)-$($arch)" + $tag_1709 = "pr$($pull_request_number)-$($os)1709-$($arch)" + $tag_1803 = "pr$($pull_request_number)-$($os)1803-$($arch)" +} else { + $tag = "$($branch_name)-$($os)-$($arch)" + $tag_1709 = "$($branch_name)-$($os)1709-$($arch)" + $tag_1803 = "$($branch_name)-$($os)1803-$($arch)" +} + +docker build ` + -t portainer/portainer:$tag ` + -f build\windows2016\nanoserver\Dockerfile . + +docker login ` + -u "$((Get-Item ENV:DOCKER_USER).Value)" ` + -p "$((Get-Item ENV:DOCKER_PASS).Value)" + +docker push portainer/portainer:$tag + +rebase-docker-image ` + portainer/portainer:$tag ` + -t portainer/portainer:$tag_1709 ` + -b microsoft/nanoserver:1709 + +rebase-docker-image ` + portainer/portainer:$tag ` + -t portainer/portainer:$tag_1803 ` + -b microsoft/nanoserver:1803 diff --git a/build/download_docker_binary.ps1 b/build/download_docker_binary.ps1 new file mode 100644 index 000000000..7ebb41ec0 --- /dev/null +++ b/build/download_docker_binary.ps1 @@ -0,0 +1,13 @@ +param ( + [string]$docker_version +) + +$ErrorActionPreference = "Stop"; + +New-Item -Path "docker-binary" -ItemType Directory | Out-Null + +$download_folder = "docker-binary" + +Invoke-WebRequest -O "$($download_folder)/docker-binaries.zip" "https://download.docker.com/win/static/stable/x86_64/docker-$($docker_version).zip" +Expand-Archive -Path "$($download_folder)/docker-binaries.zip" -DestinationPath "$($download_folder)" +Move-Item -Path "$($download_folder)/docker/docker.exe" -Destination "dist" \ No newline at end of file diff --git a/build/download_docker_binary.sh b/build/download_docker_binary.sh index cc9b94b00..bd5e01c10 100755 --- a/build/download_docker_binary.sh +++ b/build/download_docker_binary.sh @@ -19,4 +19,4 @@ else mv "${DOWNLOAD_FOLDER}/docker/docker" dist/ fi -exit 0 +exit 0 \ No newline at end of file diff --git a/build/release-linux.sh b/build/release-linux.sh new file mode 100644 index 000000000..bce48b84d --- /dev/null +++ b/build/release-linux.sh @@ -0,0 +1,45 @@ +IMAGE="$1" +ARCH="$2" +PORTAINER_VERSION="$3" +DOCKER_USER="$4" +DOCKER_PASS="$5" + +mkdir -pv portainer +cp -r dist/* portainer + +tar cvpfz "portainer-$PORTAINER_VERSION-$IMAGE-$ARCH.tar.gz" portainer +sha256sum --tag "portainer-$PORTAINER_VERSION-$IMAGE-$ARCH.tar.gz" > "portainer-$PORTAINER_VERSION-$IMAGE-$ARCH-checksum.txt" + +tag="$IMAGE-$ARCH" + +docker build -t "portainer/portainer:$IMAGE-$ARCH-$PORTAINER_VERSION" -f build/linux/Dockerfile . +docker tag "portainer/portainer:$IMAGE-$ARCH-$PORTAINER_VERSION" "portainer/portainer:$IMAGE-$ARCH" +docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" +docker push "portainer/portainer:$IMAGE-$ARCH-$PORTAINER_VERSION" +docker push "portainer/portainer:$IMAGE-$ARCH" + +if [ "${2}" == 's390x' ] ; then + docker -D manifest create "portainer/portainer:latest" \ + "portainer/portainer:linux-amd64" \ + "portainer/portainer:linux-arm" \ + "portainer/portainer:linux-arm64" \ + "portainer/portainer:linux-ppc64le" \ + "portainer/portainer:linux-s390x" \ + "portainer/portainer:windows-amd64" \ + "portainer/portainer:windows1709-amd64" \ + "portainer/portainer:windows1803-amd64" + + docker manifest push "portainer/portainer:latest" + + docker -D manifest create "portainer/portainer:${PORTAINER_VERSION}" \ + "portainer/portainer:linux-amd64-${PORTAINER_VERSION}" \ + "portainer/portainer:linux-arm-${PORTAINER_VERSION}" \ + "portainer/portainer:linux-arm64-${PORTAINER_VERSION}" \ + "portainer/portainer:linux-ppc64le-${PORTAINER_VERSION}" \ + "portainer/portainer:linux-s390x-${PORTAINER_VERSION}" \ + "portainer/portainer:windows-amd64-${PORTAINER_VERSION}" \ + "portainer/portainer:windows1709-amd64-${PORTAINER_VERSION}" \ + "portainer/portainer:windows1803-amd64-${PORTAINER_VERSION}" + + docker manifest push "portainer/portainer:${PORTAINER_VERSION}" +fi diff --git a/build/release-windows.ps1 b/build/release-windows.ps1 new file mode 100644 index 000000000..a775f24cd --- /dev/null +++ b/build/release-windows.ps1 @@ -0,0 +1,41 @@ +$ErrorActionPreference = "Stop"; +$binary = "portainer-$((Get-Item ENV:PORTAINER_VERSION).Value)-$((Get-Item ENV:IMAGE).Value)-$((Get-Item ENV:ARCH).Value).tar.gz" + +New-Item -Path portainer -ItemType Directory | Out-Null +Copy-Item -Path dist\* -Destination portainer -Recurse +tar cvpfz $binary portainer + +(Get-FileHash $binary).Hash > "portainer-$((Get-Item ENV:PORTAINER_VERSION).Value)-$((Get-Item ENV:IMAGE).Value)-$((Get-Item ENV:ARCH).Value)-checksum.txt" + +docker build ` + -t portainer/portainer:$((Get-Item ENV:IMAGE).Value)-$((Get-Item ENV:ARCH).Value)-$((Get-Item ENV:PORTAINER_VERSION).Value) ` + -f build\windows2016\nanoserver\Dockerfile . + +docker tag portainer/portainer:$((Get-Item ENV:IMAGE).Value)-$((Get-Item ENV:ARCH).Value)-$((Get-Item ENV:PORTAINER_VERSION).Value) portainer/portainer:$((Get-Item ENV:IMAGE).Value)-$((Get-Item ENV:ARCH).Value) + +docker login ` + -u "$((Get-Item ENV:DOCKER_USER).Value)" ` + -p "$((Get-Item ENV:DOCKER_PASS).Value)" + +docker push portainer/portainer:$((Get-Item ENV:IMAGE).Value)-$((Get-Item ENV:ARCH).Value)-$((Get-Item ENV:PORTAINER_VERSION).Value) +docker push portainer/portainer:$((Get-Item ENV:IMAGE).Value)-$((Get-Item ENV:ARCH).Value) + +rebase-docker-image ` + portainer/portainer:$((Get-Item ENV:IMAGE).Value)-$((Get-Item ENV:ARCH).Value) ` + -t portainer/portainer:$((Get-Item ENV:IMAGE).Value)1709-$((Get-Item ENV:ARCH).Value)-$((Get-Item ENV:PORTAINER_VERSION).Value) ` + -b microsoft/nanoserver:1709 + +rebase-docker-image ` + portainer/portainer:$((Get-Item ENV:IMAGE).Value)-$((Get-Item ENV:ARCH).Value) ` + -t portainer/portainer:$((Get-Item ENV:IMAGE).Value)1709-$((Get-Item ENV:ARCH).Value) ` + -b microsoft/nanoserver:1709 + +rebase-docker-image ` + portainer/portainer:$((Get-Item ENV:IMAGE).Value)-$((Get-Item ENV:ARCH).Value) ` + -t portainer/portainer:$((Get-Item ENV:IMAGE).Value)1803-$((Get-Item ENV:ARCH).Value)-$((Get-Item ENV:PORTAINER_VERSION).Value) ` + -b microsoft/nanoserver:1803 + +rebase-docker-image ` + portainer/portainer:$((Get-Item ENV:IMAGE).Value)-$((Get-Item ENV:ARCH).Value) ` + -t portainer/portainer:$((Get-Item ENV:IMAGE).Value)1803-$((Get-Item ENV:ARCH).Value) ` + -b microsoft/nanoserver:1803 diff --git a/gruntfile.js b/gruntfile.js index a73549c7f..e65801918 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -259,14 +259,24 @@ gruntfile_cfg.replace = { }; function shell_buildBinary(p, a) { - var binfile = 'dist/portainer-' + p + '-' + a; - return [ - 'if [ -f ' + ((p === 'windows') ? binfile + '.exe' : binfile) + ' ]; then', - 'echo "Portainer binary exists";', - 'else', - 'build/build_in_container.sh ' + p + ' ' + a + ';', - 'fi' - ].join(' '); + var binfile = 'portainer-'+p+'-'+a; + if (p === "linux") { + return [ + 'if [ -f '+(binfile)+' ]; then', + 'echo "Portainer binary exists";', + 'else', + 'build/build_binary.sh ' + p + ' ' + a + ';', + 'fi' + ].join (' ') + } else { + return [ + 'powershell -Command "& {if (Get-Item -Path '+(binfile+'.exe')+' -ErrorAction:SilentlyContinue) {', + 'Write-Host "Portainer binary exists"', + '} else {', + '& ".\\build\\build_binary.ps1" -platform '+ p +' -arch '+ a +'', + '}}"' + ].join(' ') + } } function shell_run(arch) { @@ -281,14 +291,24 @@ function shell_downloadDockerBinary(p, a) { var as = { 'amd64': 'x86_64', 'arm': 'armhf', 'arm64': 'aarch64' }; var ip = ((ps[p] === undefined) ? p : ps[p]); var ia = ((as[a] === undefined) ? a : as[a]); - var binaryVersion = ((p === 'windows' ? '<%= shippedDockerVersionWindows %>' : '<%= shippedDockerVersion %>')); - return [ - 'if [ -f ' + ((p === 'windows') ? 'dist/docker.exe' : 'dist/docker') + ' ]; then', - 'echo "Docker binary exists";', - 'else', - 'build/download_docker_binary.sh ' + ip + ' ' + ia + ' ' + binaryVersion + ';', - 'fi' - ].join(' '); + var binaryVersion = (( p === 'windows' ? '<%= shippedDockerVersionWindows %>' : '<%= shippedDockerVersion %>' )); + if (p === "linux") { + return [ + 'if [ -f '+('dist/docker')+' ]; then', + 'echo "Docker binary exists";', + 'else', + 'build/download_docker_binary.sh ' + ip + ' ' + ia + ' ' + binaryVersion + ';', + 'fi' + ].join (' ') + } else { + return [ + 'powershell -Command "& {if (Get-Item -Path '+('dist/docker.exe')+' -ErrorAction:SilentlyContinue) {', + 'Write-Host "Docker binary exists"', + '} else {', + '& ".\\build\\download_docker_binary.ps1" -docker_version '+ binaryVersion +'', + '}}"' + ].join(' ') + } } gruntfile_cfg.shell = {