mirror of
https://github.com/acedanger/finance.git
synced 2025-12-05 22:50:12 -08:00
Refactor shell scripts for improved safety and consistency; add guidelines to documentation
This commit is contained in:
112
.devcontainer/build-and-push.sh
Normal file → Executable file
112
.devcontainer/build-and-push.sh
Normal file → Executable file
@@ -1,90 +1,112 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Exit on error, undefined variables, and pipe failures
|
||||
set -euo pipefail
|
||||
# Exit on error. Append "|| true" if you expect an error.
|
||||
set -o errexit
|
||||
# Exit on error inside any functions or subshells.
|
||||
set -o errtrace
|
||||
# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
|
||||
set -o nounset
|
||||
# Catch pipeline errors
|
||||
set -o pipefail
|
||||
# Turn on traces, useful while debugging but commented out by default
|
||||
# set -o xtrace
|
||||
|
||||
# Configuration
|
||||
GITHUB_USERNAME=$1
|
||||
IMAGE_NAME="finance-devcontainer"
|
||||
IMAGE_TAG="latest"
|
||||
|
||||
# Load environment variables from .env file if it exists
|
||||
ENV_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)/.env"
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
echo "Loading environment from $ENV_FILE"
|
||||
# Use grep to find the PAT line and extract the value, handling both Unix and Windows line endings
|
||||
GITHUB_PERSONAL_ACCESS_TOKEN=$(grep -a "^GITHUB_PERSONAL_ACCESS_TOKEN=" "$ENV_FILE" | sed 's/^GITHUB_PERSONAL_ACCESS_TOKEN=//' | tr -d '\r')
|
||||
export GITHUB_PERSONAL_ACCESS_TOKEN
|
||||
fi
|
||||
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)"
|
||||
readonly ENV_FILE="${SCRIPT_DIR}/.env"
|
||||
readonly IMAGE_NAME="finance-devcontainer"
|
||||
readonly IMAGE_TAG="latest"
|
||||
|
||||
# Check for required username argument
|
||||
if [ -z "${GITHUB_USERNAME:-}" ]; then
|
||||
echo "Error: GitHub username is required"
|
||||
echo "Usage: $0 <github_username>"
|
||||
echo "Example: $0 acedanger"
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo >&2 "Error: GitHub username is required"
|
||||
echo >&2 "Usage: $0 <github_username>"
|
||||
echo >&2 "Example: $0 acedanger"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
readonly GITHUB_USERNAME="$1"
|
||||
readonly DOCKERFILE_PATH="${SCRIPT_DIR}/Dockerfile"
|
||||
readonly FULL_IMAGE_NAME="ghcr.io/${GITHUB_USERNAME}/${IMAGE_NAME}:${IMAGE_TAG}"
|
||||
|
||||
# Check for required tools
|
||||
for cmd in docker gh; do
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
echo "Error: $cmd is required but not installed"
|
||||
if ! command -v "${cmd}" >/dev/null 2>&1; then
|
||||
echo >&2 "Error: ${cmd} is required but not installed"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Load environment variables from .env file if it exists
|
||||
if [[ ! -f "${ENV_FILE}" ]]; then
|
||||
echo >&2 "Error: Environment file not found: ${ENV_FILE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Loading environment from ${ENV_FILE}"
|
||||
# Read the env file line by line to handle special characters correctly
|
||||
while IFS= read -r line || [[ -n "${line}" ]]; do
|
||||
# Skip comments and empty lines
|
||||
[[ "${line}" =~ ^[[:space:]]*# ]] && continue
|
||||
[[ -z "${line}" ]] && continue
|
||||
|
||||
# Export the variable if it's the PAT
|
||||
if [[ "${line}" =~ ^GITHUB_PERSONAL_ACCESS_TOKEN= ]]; then
|
||||
export "${line}"
|
||||
break
|
||||
fi
|
||||
done < "${ENV_FILE}"
|
||||
|
||||
# Verify PAT is loaded
|
||||
if [ -z "${GITHUB_PERSONAL_ACCESS_TOKEN:-}" ]; then
|
||||
echo "Error: GITHUB_PERSONAL_ACCESS_TOKEN is not set"
|
||||
echo "Please ensure it is defined in $ENV_FILE"
|
||||
if [[ -z "${GITHUB_PERSONAL_ACCESS_TOKEN:-}" ]]; then
|
||||
echo >&2 "Error: GITHUB_PERSONAL_ACCESS_TOKEN is not set in ${ENV_FILE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check GitHub authentication
|
||||
if ! gh auth status >/dev/null 2>&1; then
|
||||
echo "Error: Not authenticated with GitHub. Please run 'gh auth login' first"
|
||||
echo >&2 "Error: Not authenticated with GitHub. Please run 'gh auth login' first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get absolute path to Dockerfile
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)"
|
||||
DOCKERFILE_PATH="$SCRIPT_DIR/Dockerfile"
|
||||
|
||||
FULL_IMAGE_NAME="ghcr.io/$GITHUB_USERNAME/$IMAGE_NAME:$IMAGE_TAG"
|
||||
|
||||
echo "=== Building Development Container ==="
|
||||
echo "Username: $GITHUB_USERNAME"
|
||||
echo "Image: $FULL_IMAGE_NAME"
|
||||
echo "Dockerfile: $DOCKERFILE_PATH"
|
||||
echo "Username: ${GITHUB_USERNAME}"
|
||||
echo "Image: ${FULL_IMAGE_NAME}"
|
||||
echo "Dockerfile: ${DOCKERFILE_PATH}"
|
||||
echo "Using PAT: ${GITHUB_PERSONAL_ACCESS_TOKEN:0:4}... (first 4 chars)"
|
||||
|
||||
# Build the image
|
||||
echo -e "\n=> Building image..."
|
||||
if ! docker build -t "$FULL_IMAGE_NAME" -f "$DOCKERFILE_PATH" "$SCRIPT_DIR"; then
|
||||
echo "Error: Docker build failed"
|
||||
if ! docker build -t "${FULL_IMAGE_NAME}" -f "${DOCKERFILE_PATH}" "${SCRIPT_DIR}"; then
|
||||
echo >&2 "Error: Docker build failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Log in to GitHub Container Registry
|
||||
echo -e "\n=> Logging into GitHub Container Registry..."
|
||||
echo "$GITHUB_PERSONAL_ACCESS_TOKEN" | docker login ghcr.io -u "$GITHUB_USERNAME" --password-stdin
|
||||
if ! echo "${GITHUB_PERSONAL_ACCESS_TOKEN}" | docker login ghcr.io -u "${GITHUB_USERNAME}" --password-stdin; then
|
||||
echo >&2 "Error: Failed to log in to GitHub Container Registry"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Push to GitHub Container Registry
|
||||
echo -e "\n=> Pushing image to GitHub Container Registry..."
|
||||
if ! docker push "$FULL_IMAGE_NAME"; then
|
||||
echo "Error: Failed to push image"
|
||||
echo "Please check your GitHub PAT has the required permissions:"
|
||||
echo " - read:packages"
|
||||
echo " - write:packages"
|
||||
if ! docker push "${FULL_IMAGE_NAME}"; then
|
||||
echo >&2 "Error: Failed to push image"
|
||||
echo >&2 "Please check your GitHub PAT has the required permissions:"
|
||||
echo >&2 " - read:packages"
|
||||
echo >&2 " - write:packages"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\n=== Success! ==="
|
||||
echo "The development container image has been built and pushed"
|
||||
echo -e "\nTo use this image, update your devcontainer.json with:"
|
||||
echo '{
|
||||
"image": "'$FULL_IMAGE_NAME'"
|
||||
}'
|
||||
cat << EOF
|
||||
{
|
||||
"image": "${FULL_IMAGE_NAME}"
|
||||
}
|
||||
EOF
|
||||
|
||||
echo -e "\nNext steps:"
|
||||
echo "1. Update .devcontainer/devcontainer.json with the image reference above"
|
||||
|
||||
44
.devcontainer/library-scripts/load-env.sh
Executable file
44
.devcontainer/library-scripts/load-env.sh
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Exit on error. Append "|| true" if you expect an error.
|
||||
set -o errexit
|
||||
# Exit on error inside any functions or subshells.
|
||||
set -o errtrace
|
||||
# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
|
||||
set -o nounset
|
||||
# Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
|
||||
set -o pipefail
|
||||
# Turn on traces, useful while debugging but commented out by default
|
||||
# set -o xtrace
|
||||
|
||||
# Load environment variables from .env file
|
||||
readonly ENV_FILE="/workspaces/finance/.devcontainer/.env"
|
||||
|
||||
if [[ ! -f "${ENV_FILE}" ]]; then
|
||||
echo >&2 "Error: Environment file not found: ${ENV_FILE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Loading environment variables from ${ENV_FILE}"
|
||||
|
||||
# Read the env file line by line to handle special characters correctly
|
||||
while IFS= read -r line || [[ -n "${line}" ]]; do
|
||||
# Skip comments and empty lines
|
||||
[[ "${line}" =~ ^[[:space:]]*# ]] && continue
|
||||
[[ -z "${line}" ]] && continue
|
||||
|
||||
# Export the variable
|
||||
if [[ "${line}" =~ ^[[:alpha:]][[:alnum:]_]*= ]]; then
|
||||
export "${line}"
|
||||
else
|
||||
echo >&2 "Warning: Skipping invalid line: ${line}"
|
||||
fi
|
||||
done < "${ENV_FILE}"
|
||||
|
||||
# Verify PAT loaded correctly (without printing the actual token)
|
||||
if [[ -n "${GITHUB_PERSONAL_ACCESS_TOKEN:-}" ]]; then
|
||||
echo "GitHub Personal Access Token loaded successfully"
|
||||
else
|
||||
echo >&2 "ERROR: GitHub Personal Access Token not loaded"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user