Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 68 additions & 15 deletions .github/workflows/docker-openstudio.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ on:
openstudio_version:
description: 'OpenStudio version (e.g. 3.10.0)'
required: true
default: '3.11.0'
default: '3.10.0'
openstudio_sha:
description: 'OpenStudio git SHA'
required: true
default: 'dee62bf9dd'
default: '86d7e215a1'
openstudio_version_ext:
description: 'Version extension (e.g. -rc1). Leave blank for a final release. Default: -rc1'
required: false
Expand All @@ -38,10 +38,9 @@ concurrency:

env:
USE_TESTING_TIMEOUTS: "true"
OPENSTUDIO_VERSION: 3.11.0
OPENSTUDIO_SHA: dee62bf9dd
OPENSTUDIO_VERSION_EXT: "-rc1"
OPENSTUDIO_DOWNLOAD_URL: "https://openstudio-ci-builds.s3-us-west-2.amazonaws.com/develop/OpenStudio-3.11.0-rc1%2Bdee62bf9dd-Ubuntu-24.04-x86_64.deb"
OPENSTUDIO_VERSION: 3.10.0
OPENSTUDIO_SHA: 86d7e215a1
OPENSTUDIO_VERSION_EXT: ""

permissions:
contents: read
Expand All @@ -50,9 +49,11 @@ jobs:
setup:
runs-on: ubuntu-24.04
outputs:
openstudio_version: ${{ steps.resolve.outputs.openstudio_version }}
openstudio_sha: ${{ steps.resolve.outputs.openstudio_sha }}
openstudio_version_ext: ${{ steps.resolve.outputs.openstudio_version_ext }}
openstudio_version: ${{ steps.resolve.outputs.openstudio_version }}
openstudio_sha: ${{ steps.resolve.outputs.openstudio_sha }}
openstudio_version_ext: ${{ steps.resolve.outputs.openstudio_version_ext }}
openstudio_download_url: ${{ steps.resolve.outputs.openstudio_download_url }}
openstudio_download_url_arm64: ${{ steps.resolve.outputs.openstudio_download_url_arm64 }}
steps:
- name: Resolve version
id: resolve
Expand All @@ -72,18 +73,43 @@ jobs:
EXT="${{ inputs.openstudio_version_ext }}"
fi

SHA10="${SHA:0:10}"
if [ -n "${EXT}" ]; then
ESC_VERSION=$(echo "${VERSION}${EXT}" | sed 's/+/%2B/g')
DOWNLOAD_URL="https://openstudio-ci-builds.s3-us-west-2.amazonaws.com/develop/OpenStudio-${ESC_VERSION}%2B${SHA}-Ubuntu-24.04-x86_64.deb"
# S3 does not publish arm64 builds; fall back to the GitHub release asset naming
DOWNLOAD_URL_ARM64="https://github.com/NatLabRockies/OpenStudio/releases/download/v${VERSION}/OpenStudio-${ESC_VERSION}%2B${SHA10}-Ubuntu-24.04-arm64.deb"
else
DOWNLOAD_URL="https://github.com/NatLabRockies/OpenStudio/releases/download/v${VERSION}/OpenStudio-${VERSION}%2B${SHA10}-Ubuntu-24.04-x86_64.deb"
DOWNLOAD_URL_ARM64="https://github.com/NatLabRockies/OpenStudio/releases/download/v${VERSION}/OpenStudio-${VERSION}%2B${SHA10}-Ubuntu-24.04-arm64.deb"
fi

echo "openstudio_version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "openstudio_sha=${SHA}" >> "$GITHUB_OUTPUT"
echo "openstudio_version_ext=${EXT}" >> "$GITHUB_OUTPUT"
echo "openstudio_download_url=${DOWNLOAD_URL}" >> "$GITHUB_OUTPUT"
echo "openstudio_download_url_arm64=${DOWNLOAD_URL_ARM64}" >> "$GITHUB_OUTPUT"
echo "Resolved: OpenStudio ${VERSION}${EXT} (${SHA})"
echo "Resolved amd64 URL: ${DOWNLOAD_URL}"
echo "Resolved arm64 URL: ${DOWNLOAD_URL_ARM64}"

docker:
needs: setup
runs-on: ubuntu-24.04
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
os: ubuntu-24.04
- arch: arm64
os: ubuntu-24.04-arm
env:
OPENSTUDIO_VERSION: ${{ needs.setup.outputs.openstudio_version }}
OPENSTUDIO_SHA: ${{ needs.setup.outputs.openstudio_sha }}
OPENSTUDIO_VERSION_EXT: ${{ needs.setup.outputs.openstudio_version_ext }}
DEPLOY_ARCH: ${{ matrix.arch }}
OPENSTUDIO_VERSION: ${{ needs.setup.outputs.openstudio_version }}
OPENSTUDIO_SHA: ${{ needs.setup.outputs.openstudio_sha }}
OPENSTUDIO_VERSION_EXT: ${{ needs.setup.outputs.openstudio_version_ext }}
OPENSTUDIO_DOWNLOAD_URL: ${{ matrix.arch == 'arm64' && needs.setup.outputs.openstudio_download_url_arm64 || needs.setup.outputs.openstudio_download_url }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
Expand All @@ -98,9 +124,14 @@ jobs:
docker build -t openstudio:latest \
--build-arg OPENSTUDIO_VERSION=$OPENSTUDIO_VERSION \
--build-arg OPENSTUDIO_SHA=$OPENSTUDIO_SHA \
--build-arg OPENSTUDIO_DOWNLOAD_URL=$OPENSTUDIO_DOWNLOAD_URL \
--build-arg OPENSTUDIO_VERSION_EXT=$OPENSTUDIO_VERSION_EXT .
docker run openstudio:latest openstudio openstudio_version
docker run openstudio:latest /usr/local/openstudio-$OPENSTUDIO_VERSION/Radiance/bin/rtrace -version
if [ "$DEPLOY_ARCH" = "amd64" ]; then
docker run openstudio:latest /usr/local/openstudio-$OPENSTUDIO_VERSION/Radiance/bin/rtrace -version
else
echo "Skipping Radiance rtrace test on $DEPLOY_ARCH: packaged binary is not executable on arm64"
fi
docker run -v "$(pwd)":/var/simdata/openstudio openstudio:latest ruby /var/simdata/openstudio/test/test_run.rb
docker run -v "$(pwd)/test":/var/simdata/openstudio openstudio:latest ./test_gemfile.sh

Expand All @@ -113,10 +144,32 @@ jobs:
env:
DOCKER_PASS: ${{ secrets.DOCKER_PASS }}
DOCKER_USER: ${{ secrets.DOCKER_USER }}
DOCKER_MANUAL_IMAGE_TAG: ${{ inputs.docker_manual_image_tag }}

docker-manifest:
needs: [setup, docker]
runs-on: ubuntu-24.04
if: ${{ github.event_name != 'pull_request' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/custom_branch_name') && !(github.event_name == 'workflow_dispatch' && inputs.apptainer_only) }}
env:
OPENSTUDIO_VERSION: ${{ needs.setup.outputs.openstudio_version }}
OPENSTUDIO_SHA: ${{ needs.setup.outputs.openstudio_sha }}
OPENSTUDIO_VERSION_EXT: ${{ needs.setup.outputs.openstudio_version_ext }}
steps:
- uses: actions/checkout@v4

- name: merge multi-arch manifests
shell: bash
run: |
set -euo pipefail
./merge_manifests.sh
env:
DOCKER_PASS: ${{ secrets.DOCKER_PASS }}
DOCKER_USER: ${{ secrets.DOCKER_USER }}
DOCKER_MANUAL_IMAGE_TAG: ${{ inputs.docker_manual_image_tag }}

apptainer:
runs-on: ubuntu-24.04
needs: [setup, docker]
needs: [setup, docker, docker-manifest]
if: ${{ github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/custom_branch_name' }}
env:
OPENSTUDIO_VERSION: ${{ needs.setup.outputs.openstudio_version }}
Expand Down
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ LABEL maintainer="Nicholas Long nicholas.long@nrel.gov"
ARG OPENSTUDIO_VERSION=3.11.0
ARG OPENSTUDIO_VERSION_EXT="-rc1"
ARG OPENSTUDIO_SHA="dee62bf9dd"
# Automatically populated by BuildKit during multi-arch builds (amd64 / arm64).
# Used to select the correct OpenStudio .deb package when OPENSTUDIO_DOWNLOAD_URL is not provided.
ARG TARGETARCH
# If OPENSTUDIO_DOWNLOAD_URL is not provided, construct a reasonable default using the
# OpenStudio CI S3 pattern. Users can override by passing --build-arg OPENSTUDIO_DOWNLOAD_URL=...
ARG OPENSTUDIO_DOWNLOAD_URL=""
Expand Down Expand Up @@ -33,11 +36,19 @@ RUN apt-get update && apt-get install -y \
sudo \
&& if [ -z "${OPENSTUDIO_DOWNLOAD_URL}" ]; then \
ESC_VERSION=$(echo "${OPENSTUDIO_VERSION}${OPENSTUDIO_VERSION_EXT}" | sed 's/+/%2B/g'); \
if [ "${TARGETARCH}" = "arm64" ]; then \
# S3 does not publish arm64 builds; use the GitHub release asset (named -arm64).
# Mirror the workflow's setup job: GitHub URLs use the 10-char SHA.
SHA10=$(echo "${OPENSTUDIO_SHA}" | cut -c1-10); \
OPENSTUDIO_DOWNLOAD_URL="https://github.com/NatLabRockies/OpenStudio/releases/download/v${OPENSTUDIO_VERSION}/OpenStudio-${ESC_VERSION}%2B${SHA10}-Ubuntu-24.04-arm64.deb"; \
else \
# amd64: BuildKit TARGETARCH is "amd64" but the S3 asset is named -x86_64.
if [ -n "${OPENSTUDIO_SHA}" ]; then \
OPENSTUDIO_DOWNLOAD_URL="https://openstudio-ci-builds.s3.amazonaws.com/develop/OpenStudio-${ESC_VERSION}%2B${OPENSTUDIO_SHA}-Ubuntu-24.04-x86_64.deb"; \
else \
OPENSTUDIO_DOWNLOAD_URL="https://openstudio-ci-builds.s3.amazonaws.com/develop/OpenStudio-${ESC_VERSION}-Ubuntu-24.04-x86_64.deb"; \
fi; \
fi; \
fi \
&& echo "OpenStudio Package Download URL is ${OPENSTUDIO_DOWNLOAD_URL}" \
&& curl -SLO "$OPENSTUDIO_DOWNLOAD_URL" \
Expand Down
90 changes: 36 additions & 54 deletions deploy_docker.sh
Original file line number Diff line number Diff line change
@@ -1,61 +1,43 @@
#!/usr/bin/env bash
IMAGETAG=${OPENSTUDIO_VERSION}${OPENSTUDIO_VERSION_EXT}
echo "default image tag would be $IMAGETAG"
IMAGETAG=skip
DOCKER_REPO=${DOCKER_REPO:-nrel/openstudio}

# Check branch name for correct tagging
if [ "${GITHUB_REF}" == "refs/heads/develop" ]; then
IMAGETAG="develop"
elif [ "${GITHUB_REF}" == "refs/heads/2.9.X-LTS" ]; then
IMAGETAG="2.9.X-LTS"
elif [ "${GITHUB_REF}" == "refs/heads/master" ]; then
# Retrieve the version number from rails
IMAGETAG=${OPENSTUDIO_VERSION}${OPENSTUDIO_VERSION_EXT}
# Uncomment and set branch name for custom builds.
elif [ "${GITHUB_REF}" == "refs/heads/custom_branch_name" ]; then
IMAGETAG="experimental"
elif [ "${DOCKER_MANUAL_IMAGE_TAG}" == "develop" ]; then
IMAGETAG="develop"
# Builds the locally-built image, tags it with an arch suffix, and pushes it.
# The canonical (multi-arch) tags are created later by merge_manifests.sh.
#
# Required env: DOCKER_USER, DOCKER_PASS, OPENSTUDIO_VERSION, OPENSTUDIO_VERSION_EXT
# Optional env: DEPLOY_ARCH (amd64|arm64, default amd64), DOCKER_MANUAL_IMAGE_TAG
set -euo pipefail

source "$(dirname "$0")/get_image_tags.sh"
DEPLOY_ARCH=${DEPLOY_ARCH:-amd64}

# GITHUB_BASE_REF is only set on Pull Request events. Do not build those
if [ "${IMAGETAG}" == "skip" ] || [ -n "${GITHUB_BASE_REF:-}" ]; then
echo "Not on a deployable branch, this is a pull request or has been explicitly skipped"
exit 0
fi

# Check if this is a manual installer GH action
if [ ! -z "${DOCKER_MANUAL_IMAGE_TAG}" ]; then
if [ "${DOCKER_MANUAL_IMAGE_TAG}" == "develop" ]; then
IMAGETAG="develop"
elif [[ "${DOCKER_MANUAL_IMAGE_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+.*$ ]]; then
IMAGETAG="${DOCKER_MANUAL_IMAGE_TAG}"
else
IMAGETAG="dev-${DOCKER_MANUAL_IMAGE_TAG}"
fi
echo "Tagging image as ${IMAGETAG}-${DEPLOY_ARCH} and pushing to ${DOCKER_REPO}"

echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin

# Push the arch-suffixed image. The canonical tag is assembled later by the
# manifest job so that parallel amd64/arm64 pushes never clobber each other.
ARCH_TAG="${DOCKER_REPO}:${IMAGETAG}-${DEPLOY_ARCH}"
docker tag openstudio:latest "${ARCH_TAG}"
docker push "${ARCH_TAG}"

# If on develop branch, also push the develop tag pointing to this image
if [ "${IMAGETAG}" == "develop" ]; then
docker tag openstudio:latest "${DOCKER_REPO}:develop-${DEPLOY_ARCH}"
docker push "${DOCKER_REPO}:develop-${DEPLOY_ARCH}"
fi

# GITHUB_BASE_REF is only set on Pull Request events. Do not build those
if [ "${IMAGETAG}" != "skip" ] && [[ -z "${GITHUB_BASE_REF}" ]]; then
echo "Tagging image as $IMAGETAG and pushing to ${DOCKER_REPO}"

echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin
# Tag versioned image
docker tag openstudio:latest ${DOCKER_REPO}:$IMAGETAG; (( exit_status = exit_status || $? ))

# Only update and push 'latest' if this is a stable release (no extension)
if [ -z "${OPENSTUDIO_VERSION_EXT}" ]; then
echo "Stable release detected. Updating and pushing '${DOCKER_REPO}:latest'"
docker tag openstudio:latest ${DOCKER_REPO}:latest; (( exit_status = exit_status || $? ))
docker push ${DOCKER_REPO}:latest; (( exit_status = exit_status || $? ))
else
echo "Pre-release detected (extension: '${OPENSTUDIO_VERSION_EXT}'). Skipping 'latest' tag update."
fi

# Push versioned tag
docker push ${DOCKER_REPO}:$IMAGETAG; (( exit_status = exit_status || $? ))
# If on develop branch, also push the develop tag pointing to this image
if [ "${IMAGETAG}" == "develop" ] || [ "${GITHUB_REF}" == "refs/heads/develop" ]; then
docker tag openstudio:latest ${DOCKER_REPO}:develop; (( exit_status = exit_status || $? ))
docker push ${DOCKER_REPO}:develop; (( exit_status = exit_status || $? ))
fi

exit $exit_status
# Only update and push 'latest' if this is a stable release (no extension)
if [ -z "${OPENSTUDIO_VERSION_EXT}" ]; then
echo "Stable release detected. Updating and pushing '${DOCKER_REPO}:latest-${DEPLOY_ARCH}'"
docker tag openstudio:latest "${DOCKER_REPO}:latest-${DEPLOY_ARCH}"
docker push "${DOCKER_REPO}:latest-${DEPLOY_ARCH}"
else
echo "Not on a deployable branch, this is a pull request or has been explicity skipped"
echo "Pre-release detected (extension: '${OPENSTUDIO_VERSION_EXT}'). Skipping 'latest' tag update."
fi

echo "Done pushing ${DEPLOY_ARCH} artifacts for ${IMAGETAG}"
36 changes: 36 additions & 0 deletions get_image_tags.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# Determines the image tag to use based on the branch and manual-tag inputs.
# This file is sourced by deploy_docker.sh and merge_manifests.sh; it sets
# IMAGETAG (or "skip" when nothing should be deployed/merged) and DOCKER_REPO.
#
# Usage: source "$(dirname "$0")/get_image_tags.sh"
set -euo pipefail

IMAGETAG=skip
DOCKER_REPO=${DOCKER_REPO:-nrel/openstudio}

# Check branch name for correct tagging
if [ "${GITHUB_REF}" == "refs/heads/develop" ]; then
IMAGETAG="develop"
elif [ "${GITHUB_REF}" == "refs/heads/2.9.X-LTS" ]; then
IMAGETAG="2.9.X-LTS"
elif [ "${GITHUB_REF}" == "refs/heads/master" ]; then
# Retrieve the version number from the workflow env
IMAGETAG=${OPENSTUDIO_VERSION}${OPENSTUDIO_VERSION_EXT}
# Uncomment and set branch name for custom builds.
elif [ "${GITHUB_REF}" == "refs/heads/custom_branch_name" ]; then
IMAGETAG="experimental"
elif [ "${DOCKER_MANUAL_IMAGE_TAG}" == "develop" ]; then
IMAGETAG="develop"
fi

# Check if this is a manual installer GH action
if [ ! -z "${DOCKER_MANUAL_IMAGE_TAG:-}" ]; then
if [ "${DOCKER_MANUAL_IMAGE_TAG}" == "develop" ]; then
IMAGETAG="develop"
elif [[ "${DOCKER_MANUAL_IMAGE_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+.*$ ]]; then
IMAGETAG="${DOCKER_MANUAL_IMAGE_TAG}"
else
IMAGETAG="dev-${DOCKER_MANUAL_IMAGE_TAG}"
fi
fi
42 changes: 42 additions & 0 deletions merge_manifests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env bash
# Merges the arch-suffixed images pushed by deploy_docker.sh into canonical
# multi-arch manifests (e.g. nrel/openstudio:3.10.0-amd64 + -arm64 -> :3.10.0).
# Requires docker buildx (bundled with Docker CLI 19.03+).
#
# Required env: DOCKER_USER, DOCKER_PASS, OPENSTUDIO_VERSION, OPENSTUDIO_VERSION_EXT
# Optional env: DOCKER_MANUAL_IMAGE_TAG
set -euo pipefail

source "$(dirname "$0")/get_image_tags.sh"

if [ "${IMAGETAG}" == "skip" ] || [ -n "${GITHUB_BASE_REF:-}" ]; then
echo "Nothing to merge — not on a deployable branch"
exit 0
fi

echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin

merge() {
local canonical=$1
echo "Creating multi-arch manifest ${DOCKER_REPO}:${canonical}"
docker buildx imagetools create \
-t "${DOCKER_REPO}:${canonical}" \
"${DOCKER_REPO}:${canonical}-amd64" \
"${DOCKER_REPO}:${canonical}-arm64"
}

merge "${IMAGETAG}"

if [ "${IMAGETAG}" == "develop" ]; then
merge "develop"
fi

# Only update 'latest' if this is a stable release (no extension)
if [ -z "${OPENSTUDIO_VERSION_EXT}" ]; then
echo "Stable release detected. Updating multi-arch 'latest'."
merge "latest"
else
echo "Pre-release detected (extension: '${OPENSTUDIO_VERSION_EXT}'). Skipping 'latest' manifest."
fi

echo "Done merging multi-arch manifests for ${IMAGETAG}"
Loading