Skip to content
Merged
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
5 changes: 4 additions & 1 deletion anaconda/build.sh
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
${PYTHON} setup.py install --single-version-externally-managed --record=record.txt
# Run setup.py in isolated mode (-I) so the build does not pick up stray
# modules from the working directory. -I is available on all supported
# Pythons (>=3.4), unlike -P/PYTHONSAFEPATH which require Python >=3.11.
${PYTHON} -I setup.py install --single-version-externally-managed --record=record.txt
36 changes: 30 additions & 6 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
# This script builds snowflake-telemetry-python for release. It is called from
# a Jenkins job called SnowflakeTelemetryPythonPackageBuilder.
#
# Prequisites:
# Prerequisites:
# - run from a pristine git checkout (this script refuses to build from a
# workspace with modified, untracked, or ignored files; see
# scripts/release_lib.sh)
# - activate a conda environment
# - have conda-build installed, e.g. `conda install conda-build`
# - have conda-verify installed, e.g. `conda install conda-verify`
#
# Then, run this script.
#
Expand All @@ -18,12 +20,30 @@
# conda activate my-conda-build-environment
# # cd into the snowflake-telemetry-python git root dir
# export SNOWFLAKE_TELEMETRY_DIR=$(pwd)
#
# For local test builds only, the workspace hygiene check can be bypassed with:
# export SNOWFLAKE_TELEMETRY_ALLOW_DIRTY_WORKSPACE=1
# Never set this in the Jenkins release job.

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${REPO_ROOT}/scripts/release_lib.sh"

# Remove our own previous build output so it does not trip the hygiene gate.
rm -rf ./anaconda/dist

# Refuse to build unless the checkout is pristine (no modified, untracked, or
# ignored files), so release artifacts contain only committed sources. The
# explicit exit keeps this guard effective even if the script is invoked as
# `bash build.sh` without -e.
assert_clean_workspace "${REPO_ROOT}" || exit 1

make_conda_build () {
# set default build number to 0, if SNOWFLAKE_TELEMETRY_BUILD_NUMBER is not set
echo "Start building snowflake-telemetry-python package with build_number: ${SNOWFLAKE_TELEMETRY_BUILD_NUMBER:=0}"
# conda build takes GIT_HASH as environment variable and embed it into the build package name
GIT_HASH=$(git rev-parse --short HEAD) SNOWFLAKE_TELEMETRY_BUILD_NUMBER=${SNOWFLAKE_TELEMETRY_BUILD_NUMBER:=0} conda build ./anaconda --output-folder ./anaconda/dist
# conda build takes GIT_HASH as environment variable and embed it into the build package name.
# Record the full HEAD commit so the artifact can be traced back to an exact,
# immutable revision (a short hash is ambiguous enough to collide).
GIT_HASH=$(git -C "${REPO_ROOT}" rev-parse HEAD) SNOWFLAKE_TELEMETRY_BUILD_NUMBER=${SNOWFLAKE_TELEMETRY_BUILD_NUMBER:=0} conda build ./anaconda --output-folder ./anaconda/dist
}

BUILD_CONDA_FORMAT=false
Expand All @@ -37,8 +57,8 @@ done
# set up private channel to make opentelemetry dependencies available
conda config --add channels https://repo.anaconda.com/pkgs/snowflake/

# clean up the dist directory
rm -rf ./anaconda/dist
# create a clean dist directory (previous output was removed before the
# workspace hygiene gate above)
mkdir -p ./anaconda/dist

if [ "$BUILD_CONDA_FORMAT" = true ] ; then
Expand All @@ -52,6 +72,10 @@ else
make_conda_build
fi

# Bind the build outputs to SHA-256 digests so downstream release steps can
# verify that what gets published is what this build produced.
write_sha256_manifest ./anaconda/dist || exit 1

# clean up the conda environment
conda config --remove channels https://repo.anaconda.com/pkgs/snowflake/
conda build purge
20 changes: 20 additions & 0 deletions pypi-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,22 @@
# source .venv/bin/activate
# # cd into the snowflake-telemetry-python git root dir
# export SNOWFLAKE_TELEMETRY_DIR=$(pwd)
#
# For local test builds only, the workspace hygiene check can be bypassed with:
# export SNOWFLAKE_TELEMETRY_ALLOW_DIRTY_WORKSPACE=1
# Never set this in the Jenkins release job.

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${REPO_ROOT}/scripts/release_lib.sh"

# Remove our own previous build outputs so they do not trip the hygiene gate.
rm -rf ./dist ./build venv_* src/*.egg-info

# Refuse to build unless the checkout is pristine (no modified, untracked, or
# ignored files), so release artifacts contain only committed sources. The
# explicit exit keeps this guard effective even if the script is invoked as
# `bash pypi-build.sh` without -e.
assert_clean_workspace "${REPO_ROOT}" || exit 1

VENV_DIR=venv_$(date +%s)
python3 -m venv ${VENV_DIR}
Expand All @@ -35,5 +51,9 @@ mkdir ./dist
echo "Start building snowflake-telemetry-python package with build_number: ${SNOWFLAKE_TELEMETRY_BUILD_NUMBER:=0}"
SNOWFLAKE_TELEMETRY_BUILD_NUMBER=${SNOWFLAKE_TELEMETRY_BUILD_NUMBER:=0} python3 -m build

# Bind the build outputs to SHA-256 digests so downstream release steps can
# verify that what gets published is what this build produced.
write_sha256_manifest ./dist || exit 1

deactivate
rm -rf ${VENV_DIR}
81 changes: 81 additions & 0 deletions scripts/release_lib.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Guards for the Jenkins release build scripts (build.sh and pypi-build.sh).
#
# This file is sourced by those scripts. It must only define functions and
# have no side effects when sourced.

# assert_clean_workspace <repo_root>
#
# Return 0 only when the git working tree at <repo_root> is pristine: no
# modified, staged, untracked, or ignored files. Otherwise print the offending
# entries to stderr and return 1.
#
# Release builds must produce artifacts from committed sources only, so the
# build refuses to run from a checkout with any leftover or unreviewed files.
#
# For local test builds only, set SNOWFLAKE_TELEMETRY_ALLOW_DIRTY_WORKSPACE=1
# to bypass this check. Never set it in the Jenkins release job.
assert_clean_workspace() {
local repo_root="${1:-}"

if [ -z "$repo_root" ]; then
echo "assert_clean_workspace: no repository path given; refusing to build." >&2
return 1
fi

if [ "${SNOWFLAKE_TELEMETRY_ALLOW_DIRTY_WORKSPACE:-0}" = "1" ]; then
echo "WARNING: SNOWFLAKE_TELEMETRY_ALLOW_DIRTY_WORKSPACE=1 is set; skipping the workspace hygiene check." >&2
echo "WARNING: never set this for official release builds." >&2
return 0
fi

local status
if ! status="$(git -C "$repo_root" status --porcelain --untracked-files=all --ignored=matching 2>&1)"; then
echo "Unable to determine the git state of $repo_root; refusing to build." >&2
echo "$status" >&2
return 1
fi

if [ -n "$status" ]; then
echo "Refusing to build release artifacts from a non-pristine workspace: $repo_root" >&2
echo "The following modified, untracked, or ignored (!!) files are present:" >&2
echo "$status" >&2
echo "Release builds must run from a pristine checkout so that artifacts" >&2
echo "contain only committed sources." >&2
Comment thread
sfc-gh-eukim marked this conversation as resolved.
echo "For local builds, set SNOWFLAKE_TELEMETRY_ALLOW_DIRTY_WORKSPACE=1 to skip this check." >&2
return 1
fi
}

# write_sha256_manifest <dist_dir>
#
# Write <dist_dir>/SHA256SUMS containing the SHA-256 digest of every file
# under <dist_dir>, so downstream release steps can verify that the artifacts
# they publish are bit-for-bit what this build produced. Fails if no artifacts
# are present.
write_sha256_manifest() {
local dist_dir="${1:-}"

if [ -z "$dist_dir" ] || [ ! -d "$dist_dir" ]; then
echo "write_sha256_manifest: '$dist_dir' is not a directory." >&2
return 1
fi

local sha256_cmd
if command -v sha256sum >/dev/null 2>&1; then
sha256_cmd="sha256sum"
else
# macOS (local test builds) ships shasum instead of sha256sum.
sha256_cmd="shasum -a 256"
fi

local files
files="$(cd "$dist_dir" && find . -type f ! -name SHA256SUMS -print | sort)"
if [ -z "$files" ]; then
echo "No build artifacts found under $dist_dir" >&2
return 1
fi

(cd "$dist_dir" && printf '%s\n' "$files" | while IFS= read -r artifact; do
$sha256_cmd "$artifact"
done > SHA256SUMS)
}
Loading