Changeset - 1d96e4a605b9
[Not reviewed]
0 1 0
Branko Majic (branko) - 2 years ago 2022-08-21 15:15:24
branko@majic.rs
[factorio_development.sh] Added command for aborting the release process:

- Command cleans-up the local git repository from all release
artifacts.
- Pull out functions for fetching some basic information to reduce
code duplication, and refactor the exsiting code to use the helper
functions.
- Treat build configuration variables as globals.
1 file changed with 327 insertions and 49 deletions:
0 comments (0 inline, 0 general) First comment
games/factorio_development.sh
Show inline comments
 
@@ -19,23 +19,24 @@
 
#
 

	
 
# Treat unset variables as errors.
 
set -u
 

	
 
PROGRAM="factorio_development.sh"
 
VERSION="0.0.3"
 
VERSION="0.0.4"
 

	
 
function usage() {
 
    cat <<EOF
 
$PROGRAM $VERSION, helper tool for development of Factorio mods
 

	
 
Usage:
 

	
 
  $PROGRAM [OPTIONS] init MOD_DIRECTORY_PATH
 
  $PROGRAM [OPTIONS] build [MOD_DIRECTORY_PATH]
 
  $PROGRAM [OPTIONS] release [MOD_DIRECTORY_PATH]
 
  $PROGRAM [OPTIONS] abort-release [MOD_DIRECTORY_PATH]
 

	
 
EOF
 
}
 

	
 
function short_help() {
 
    cat <<EOF
 
@@ -151,12 +152,32 @@ release MOD_VERSION [MOD_DIRECTORY_PATH]
 
  tags using the git_version_tag_prefix option in the build
 
  configuration file (build.cfg). This can be used to, for example,
 
  have the tags created as "release/1.0.0" or "v1.0.0" instead of
 
  default "1.0.0".
 

	
 

	
 
abort-release [MOD_DIRECTORY_PATH]
 

	
 
  Arguments:
 

	
 
    MOD_DIRECTORY_PATH (path to base directory)
 

	
 
  Aborts release process (started with the release command) for a
 
  mod. Expects (optional) path to mod base directory. Default is to
 
  use working directory as mod directory path.
 

	
 
  Must be run from a release branch.
 

	
 
  Aborting the release will:
 

	
 
  - Undo all current changes to git-managed files.
 
  - Drop version tag associated with the release branch.
 
  - Switch back to main branch.
 
  - Drop the release branch.
 

	
 

	
 
$PROGRAM accepts the following options:
 

	
 
    -q
 
        Quiet mode.
 
    -d
 
        Enable debug mode.
 
@@ -191,12 +212,226 @@ $PROGRAM, version $VERSION
 
+-----------------------------------------------------------------------+
 

	
 
EOF
 
}
 

	
 

	
 
# Utilities
 
# =========
 

	
 
#
 
# Finds the source directory under the passed-in base directory.
 
#
 
# Arguments:
 
#
 
#   $1 (base_dir)
 
#     Base mod directory.
 
#
 
# Outputs:
 
#
 
#   Path to mod sources directory.
 
#
 
# Returns:
 
#
 
#   0 on success, 1 otherwise.
 
#
 
function get_source_directory() {
 
    local base_dir="$1"
 

	
 
    local source_dir
 

	
 
    if [[ -d $base_dir/src ]]; then
 
        source_dir="src"
 
    else
 
        source_dir="."
 
    fi
 

	
 
    if [[ ! -d $source_dir ]]; then
 
        error "Could not locate source directory."
 
        return 1
 
    fi
 

	
 
    echo "$source_dir"
 
    return 0
 
}
 

	
 

	
 
#
 
# Finds the info file under the passed-in base directory.
 
#
 
# Arguments:
 
#
 
#   $1 (base_dir)
 
#     Base mod directory.
 
#
 
# Outputs:
 
#
 
#   Path to info file.
 
#
 
# Returns:
 
#
 
#   0 on success, 1 otherwise.
 
#
 
function get_info_file() {
 
    local base_dir="$1"
 

	
 
    local info_file
 

	
 
    if [[ -d $base_dir/src ]]; then
 
        info_file="$base_dir/src/info.json"
 
    else
 
        info_file="$base_dir/info.json"
 
    fi
 

	
 
    if [[ ! -f $info_file ]]; then
 
        error "Could not locate info file under: $info_file"
 
        return 1
 
    fi
 

	
 
    echo "$info_file"
 
    return 0
 
}
 

	
 

	
 
#
 
# Finds the changelog file under the passed-in base directory.
 
#
 
# Arguments:
 
#
 
#   $1 (base_dir)
 
#     Base mod directory.
 
#
 
# Outputs:
 
#
 
#   Path to changelog file.
 
#
 
# Returns:
 
#
 
#   0 on success, 1 otherwise.
 
#
 
function get_changelog_file() {
 
    local base_dir="$1"
 

	
 
    local changelog_file
 

	
 
    if [[ -d $base_dir/src ]]; then
 
        changelog_file="$base_dir/src/changelog.txt"
 
    else
 
        changelog_file="$base_dir/changelog.txt"
 
    fi
 

	
 
    if [[ ! -f $changelog_file ]]; then
 
        error "Could not locate changelog file under: $changelog_file"
 
        return 1
 
    fi
 

	
 
    echo "$changelog_file"
 
    return 0
 
}
 

	
 

	
 
#
 
# Loads build configuration from the passed-in base directory.
 
#
 
# Arguments:
 
#
 
#   $1 (base_dir)
 
#     Base mod directory.
 
#
 
# Returns:
 
#
 
#   0 on success, 1 otherwise.
 
#
 
function load_build_configuration() {
 
    build_config="$base_dir/build.cfg"
 

	
 
    # Set default values to ensure they are set.
 
    declare -g IGNORE_PATHS=()
 
    declare -g GIT_VERSION_TAG_PREFIX=""
 

	
 
    # Read build configuration.
 
    # shellcheck disable=SC1090 # build configuration file is create per-mod directory
 
    if [[ -f $build_config ]] && ! source "$build_config"; then
 
        error "Failed to load build configuration from: $build_config"
 
        return 1
 
    fi
 

	
 
    return 0
 
}
 

	
 

	
 
#
 
# Determines the main branch name (should be master/main/devel).
 
#
 
#
 
# Arguments:
 
#
 
#   $1 (base_dir)
 
#     Mod base directory.
 
#
 
# Outputs:
 
#
 
#   Branch name.
 
#
 
# Returns:
 
#
 
#   0 on success, 1 otherwise.
 
#
 
function get_main_branch() {
 
    local base_dir="$1"
 

	
 
    local candidates=(
 
        "master"
 
        "main"
 
        "devel"
 
    )
 

	
 
    local candidate
 

	
 
    for candidate in "${candidates[@]}"; do
 
        if git -C "$base_dir" rev-parse --abbrev-ref "$candidate" >/dev/null 2>&1; then
 
            echo "$candidate"
 
            return 0
 
        fi
 
    done
 

	
 
    error "Could not determine main branch."
 

	
 
    return 1
 
}
 

	
 

	
 
#
 
# Determines the current branch name.
 
#
 
#
 
# Arguments:
 
#
 
#   $1 (base_dir)
 
#     Mod base directory.
 
#
 
# Outputs:
 
#
 
#   Branch name.
 
#
 
# Returns:
 
#
 
#   0 on success, 1 otherwise.
 
#
 
function get_current_branch() {
 
    local base_dir="$1"
 

	
 
    if ! git -C "$base_dir" rev-parse --abbrev-ref "HEAD"; then
 
        error "Could not determine current branch name."
 
        return 1
 
    fi
 

	
 
    return 0
 
}
 

	
 

	
 
# Commands
 
# ========
 

	
 
#
 
# Initialises mod directory structure.
 
#
 
@@ -304,21 +539,21 @@ SOFTWARE.
 
EOF
 

	
 
    cat <<EOF > "$base_dir/build.cfg"
 
# -*- mode: sh-mode; sh-shell: bash -*-
 

	
 
# Specify list of paths to exclude from the built release archives.
 
ignore_paths=(
 
IGNORE_PATHS=(
 
    ".gitignore"
 
    "build.cfg"
 
)
 

	
 
# Specify prefix to use in front of versions when tagging releases
 
# (for example if tags should be of format vX.Y.Z as opposed to
 
# X.Y.Z).
 
git_version_tag_prefix=""
 
GIT_VERSION_TAG_PREFIX=""
 
EOF
 

	
 
    cat <<EOF > "$base_dir/.gitignore"
 
# Ignore IDE and backup files.
 
*~
 
.#*
 
@@ -377,44 +612,27 @@ EOF
 
#
 
function command_build() {
 
    local base_dir="$1"
 

	
 
    local error_count=0
 

	
 
    declare -a ignore_paths
 
    declare -a mod_files
 

	
 
    local source_dir dist_dir build_dir info_file target_dir archive_file build_config
 
    local mod_name mod_version
 
    local path mod_file mod_file_path
 

	
 
    # Calculate absolute paths to various directories and artifacts.
 
    base_dir=$(readlink -f "$base_dir")
 
    build_dir="$base_dir/build"
 
    dist_dir="$base_dir/dist"
 
    build_config="$base_dir/build.cfg"
 

	
 
    # Read build configuration.
 
    # shellcheck disable=SC1090 # build configuration file is create per-mod directory
 
    if [[ -f $build_config ]] && ! source "$build_config"; then
 
        error "Failed to load build configuration from: $build_config"
 
        return 1
 
    fi
 

	
 
    if [[ -d $base_dir/src ]]; then
 
        source_dir="src"
 
        info_file="$base_dir/src/info.json"
 
    else
 
        source_dir="."
 
        info_file="$base_dir/info.json"
 
    fi
 
    load_build_configuration "$base_dir" || return 1
 

	
 
    if [[ ! -f $info_file ]]; then
 
        error "Could not locate info file under: $info_file"
 
        return 1
 
    fi
 
    source_dir=$(get_source_directory "$base_dir") || return 1
 
    info_file=$(get_info_file "$base_dir") || return 1
 

	
 
    # Extract modpack name and version
 
    if ! jq . "$info_file" > /dev/null; then
 
        error "Could not parse mod info file: $info_file"
 
        return 1
 
    fi
 
@@ -431,13 +649,14 @@ function command_build() {
 
    archive_file="${dist_dir}/${mod_name}_${mod_version}.zip"
 

	
 
    # Create list of files to package. Exclude development files from the
 
    # build.
 
    readarray -t mod_files < <(git -C "$base_dir" ls-files)
 

	
 
    for path in "${ignore_paths[@]}"; do
 
    # IGNORE_PATHS comes from build configuration.
 
    for path in "${IGNORE_PATHS[@]}"; do
 
        for i in "${!mod_files[@]}"; do
 
            if [[ -d $path && ${mod_files[i]} == $path/* ]] || [[ ${mod_files[i]} == "$path" ]]; then
 
                unset "mod_files[i]"
 
            fi
 
        done
 
    done
 
@@ -527,17 +746,14 @@ function command_build() {
 
#   0 on success, 1 otherwise.
 
#
 
function command_release() {
 
    local version="$1"
 
    local base_dir="$2"
 

	
 
    # Prefix can be overridden via build configuration file.
 
    local git_version_tag_prefix=""
 

	
 
    local info_file changelog_file build_config
 
    local current_branch release_branch
 
    local main_branch current_branch release_branch
 

	
 
    build_config="$base_dir/build.cfg"
 

	
 
    # Read build configuration.
 
    # shellcheck disable=SC1090 # build configuration file is create per-mod directory
 
    if [[ -f $build_config ]] && ! source "$build_config"; then
 
@@ -545,32 +761,20 @@ function command_release() {
 
        return 1
 
    fi
 

	
 
    current_branch=$(git -C "$base_dir" rev-parse --abbrev-ref HEAD)
 
    release_branch="release-${version}"
 

	
 
    if [[ -d $base_dir/src ]]; then
 
        info_file="$base_dir/src/info.json"
 
        changelog_file="$base_dir/src/changelog.txt"
 
    else
 
        info_file="$base_dir/info.json"
 
        changelog_file="$base_dir/changelog.txt"
 
    fi
 

	
 
    if [[ ! -f $info_file ]]; then
 
        error "Could not locate info file under: $info_file"
 
        return 1
 
    fi
 

	
 
    if [[ ! -f $changelog_file ]]; then
 
        error "Could not locate changelog file under: $changelog_file"
 
        return 1
 
    fi
 
    source_dir=$(get_source_directory "$base_dir") || return 1
 
    info_file=$(get_info_file "$base_dir") || return 1
 
    changelog_file=$(get_changelog_file "$base_dir") || return 1
 
    current_branch=$(get_current_branch "$base_dir") || return 1
 
    main_branch=$(get_main_branch "$base_dir") || return 1
 

	
 
    if [[ $current_branch != master && $current_branch != main && $current_branch != devel ]]; then
 
        error "Releases must be based off of the master/main/devel branch."
 
    if [[ $current_branch != "$main_branch" ]]; then
 
        error "Releases must be based off of the main branch."
 
        return 1
 
    fi
 

	
 
    if [[ $(git -C "$base_dir" status --short) != "" ]]; then
 
        error "Releases must be based off of a clean git working tree."
 
        return 1
 
@@ -610,16 +814,17 @@ function command_release() {
 

	
 
    # Build the release.
 
    if ! command_build "$base_dir"; then
 
        return 1
 
    fi
 

	
 
    # Commit the changes and create a tag.
 
    # Commit the changes and create a tag. GIT_VERSION_TAG_PREFIX
 
    # comes from build configuration.
 
    if ! git -C "$base_dir" add "$changelog_file" "$info_file" || \
 
       ! git -C "$base_dir" commit --edit -m "Prepared release $version." || \
 
       ! git -C "$base_dir" tag -a -m "Release $version." "${git_version_tag_prefix}${version}"; then
 
       ! git -C "$base_dir" tag -a -m "Release $version." "${GIT_VERSION_TAG_PREFIX}${version}"; then
 

	
 
        error "Failed to create release commit and tag."
 
        return 1
 
    fi
 

	
 
    # Switch back to development version.
 
@@ -638,12 +843,70 @@ $(< "$changelog_file")
 
    fi
 

	
 
    return 0
 
}
 

	
 

	
 
#
 
# Aborts the current release process.
 
#
 
# Arguments:
 
#
 
#   $1 (base_dir)
 
#     Base (top-level) directory with the mod files.
 
#
 
# Returns:
 
#
 
#   0 on success, 1 otherwise.
 
#
 
function command_abort_release() {
 
    local base_dir="$1"
 

	
 
    local info_file changelog_file build_config
 
    local current_branch release_branch version
 

	
 
    load_build_configuration "$base_dir" || return 1
 
    main_branch=$(get_main_branch "$base_dir") || return 1
 
    release_branch=$(get_current_branch "$base_dir") || return 1
 
    version="${release_branch##release-}"
 

	
 
    if [[ ! $release_branch =~ ^release-[[:digit:]]+\.[[:digit:]]+\.[[:digit:]] ]]; then
 
        error "Current branch is not a release branch."
 
        return 1
 
    fi
 

	
 
    # Drop the tag.
 
    if [[ -n $(git -C "$base_dir" tag --list "${GIT_VERSION_TAG_PREFIX}${version}") ]] &&
 
       ! git tag --delete "${GIT_VERSION_TAG_PREFIX}${version}"; then
 

	
 
        error "Failed to drop the git tag: ${GIT_VERSION_TAG_PREFIX}${version}"
 
        return 1
 
    fi
 

	
 
    # Reset working directory, dropping eventual local changes.
 
    if ! git -C "$base_dir" reset --hard HEAD; then
 
        error "Failed to reset working directory."
 
        return 1
 
    fi
 

	
 
    # Switch back to main branch.
 
    if ! git -C "$base_dir" checkout "$main_branch"; then
 
        error "Failed to switch to main branch."
 
        return 1
 
    fi
 

	
 
    # Drop the release branch.
 
    if ! git -C "$base_dir" branch --delete --force "$release_branch"; then
 
        error "Failed to remove the release branch."
 
        return 1
 
    fi
 

	
 
    return 0
 
}
 

	
 

	
 
# Set-up colours for message printing if we're not piping and terminal is
 
# capable of outputting the colors.
 
_COLOR_TERMINAL=$(tput colors 2>&1)
 
if [[ -t 1 ]] && (( _COLOR_TERMINAL > 0 )); then
 
    _TEXT_BOLD=$(tput bold)
 
    _TEXT_WHITE=$(tput setaf 7)
 
@@ -779,12 +1042,27 @@ elif [[ $COMMAND == release ]]; then
 
    fi
 

	
 
    if ! command_release "$MOD_VERSION" "$MOD_DIRECTORY_PATH"; then
 
        exit "$ERROR_GENERAL"
 
    fi
 

	
 
elif [[ $COMMAND == abort-release ]]; then
 

	
 
    MOD_DIRECTORY_PATH="${1:-.}"
 
    shift
 

	
 
    # Ensure that passed-in base directory is the repository root.
 
    if [[ ! -d $MOD_DIRECTORY_PATH/.git ]]; then
 
        error "Passed-in path does not point to base directory of the mod (must contain the .git sub-directory)."
 
        exit "$ERROR_ARGUMENTS"
 
    fi
 

	
 
    if ! command_abort_release "$MOD_DIRECTORY_PATH"; then
 
        exit "$ERROR_GENERAL"
 
    fi
 

	
 
else
 

	
 
    error "Unsupported command: $COMMAND"
 
    exit "$ERROR_ARGUMENTS"
 

	
 
fi
0 comments (0 inline, 0 general) First comment
You need to be logged in to comment. Login now