Changeset - b14d3faa45c4
[Not reviewed]
0 1 0
Branko Majic (branko) - 2 years ago 2022-08-21 15:41:25
branko@majic.rs
[factorio_development.sh] Added (personal) workaround for tag signing:

- Older versions of git (<2.23) do not have the tag.gpgSign
option. Try to emulate it by appending the --sign option if it is
set in git configuration.
1 file changed with 8 insertions and 1 deletions:
0 comments (0 inline, 0 general) First comment
games/factorio_development.sh
Show inline comments
 
@@ -661,389 +661,396 @@ function command_build() {
 

	
 
    load_build_configuration "$base_dir" || return 1
 

	
 
    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
 
    mod_name=$(get_mod_name "$base_dir") || return 1
 
    mod_version=$(jq -r ".version" "$info_file")
 

	
 
    # Validate version string format.
 
    if [[ ! $mod_version =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$ ]]; then
 
        error "Invalid mod version read from info file: $mod_version"
 
        return 1
 
    fi
 

	
 
    target_dir="${build_dir}/${mod_name}_${mod_version}"
 
    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)
 

	
 
    # 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
 

	
 
    # Fix the index gaps in file list array.
 
    mod_files=("${mod_files[@]}")
 

	
 
    # Validate the files.
 
    error_count=0
 

	
 
    for mod_file in "${mod_files[@]}"; do
 
        mod_file_path="${base_dir}/${mod_file}"
 

	
 
        if [[ $mod_file_path =~ .*\.lua ]] && ! luac -o /dev/null "$mod_file_path"; then
 
            (( error_count += 1 ))
 
            error "Validation failed for file: $mod_file"
 
        fi
 

	
 
        if [[ $mod_file_path =~ .*\.json ]] && ! python -m json.tool "$mod_file_path" > /dev/null; then
 
            (( error_count += 1 ))
 
            error "Validation failed for file: $mod_file"
 
        fi
 
    done
 

	
 
    if [[ $error_count != 0 ]]; then
 
        return 1
 
    fi
 

	
 
    # Do some basic validation so we do not overwrite things by mistake.
 
    if [[ -e $archive_file ]]; then
 
        error "Output archive already exists: $archive_file"
 
        return 1
 
    fi
 

	
 
    info "Building release: $mod_version"
 

	
 
    # Set-up the necessary directories.
 
    rm -rf "$target_dir"
 
    mkdir -p "$target_dir"
 
    mkdir -p "$dist_dir"
 

	
 
    # Copy the files.
 
    for mod_file in "${mod_files[@]}"; do
 
        if ! (cd "$base_dir" && install -m 0644 -D "$mod_file" "${target_dir}/${mod_file%%${source_dir}/}"); then
 
            error "Failed to copy the file: $mod_file"
 
            return 1
 
        fi
 
    done
 

	
 
    # Move sources to base directory.
 
    if [[ $source_dir != . ]]; then
 
        mv -n "${target_dir}/${source_dir}"/* "${target_dir}"
 
        if ! rmdir "${target_dir}/${source_dir}"; then
 
            error "Failed to remove directory: ${target_dir}/${source_dir}"
 
            return 1
 
        fi
 
    fi
 

	
 
    # Zip the files.
 
    if ! (cd "$build_dir/" && zip -q -r "$archive_file" "$(basename "$target_dir")"); then
 
        error "Could not prepare the release archive."
 
        return 1
 
    fi
 

	
 
    rm -rf "$target_dir"
 

	
 
    success "Release built and placed under: $archive_file"
 
}
 

	
 

	
 
#
 
# Releases a mod version. Takes care of creating separate branch,
 
# making versioning changes/updates to mod information file and
 
# changelog, creating the tags, and even switching back the mod to
 
# development version.
 
#
 
# Arguments:
 
#
 
#   $1 (version)
 
#     Version of mod to release.
 
#
 
#   $2 (base_dir)
 
#     Base (top-level) directory with the mod files.
 
#
 
# Returns:
 
#
 
#   0 on success, 1 otherwise.
 
#
 
function command_release() {
 
    local version="$1"
 
    local base_dir="$2"
 

	
 
    local info_file changelog_file build_config changelog
 
    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
 
        error "Failed to load build configuration from: $build_config"
 
        return 1
 
    fi
 

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

	
 
    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 != "$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
 
    fi
 

	
 
    if ! git -C "$base_dir" checkout -b "$release_branch"; then
 
        error "Failed to create release branch: $release_branch"
 
        return 1
 
    fi
 

	
 
    # Update versioning information in info file and changelog.
 
    sed -i -e "s/999.999.999/$version/" "$info_file" "$changelog_file"
 

	
 
    # Update release date.
 
    sed -i -e "s/9999-99-99/$(date +%Y-%m-%d)/" "$changelog_file"
 

	
 
    # Drop empty changelog sections. Changelog sections begin with two
 
    # whitespaces at line beginning, followed by a non-whitespace
 
    # character.
 
    #
 
    # First sed expression:
 
    #
 
    # 1. Finds a section line.
 
    # 2. Reads the next line and adds it to pattern space. If the next
 
    #    line is not a section line, outputs the section it found
 
    #    (P). Otherwise it deletes the matched section line (D).
 
    # 3. Finally, it checks if the next line read (in step 2) is also
 
    #    a section line, and if it is, repeats the process for it (has
 
    #    to be done via goto directive since sed cannot be told to
 
    #    re-read the lines once they have been read with the N
 
    #    directive).
 
    #
 
    # Second sed expression deals with empty sections at the end of
 
    # the file (special case).
 
    sed -i -E -e '/^  [^ ]/{: checknext; N; /\n   /P; D; /^  [^ ]/b checknext}' "$changelog_file"
 
    sed -i -z -E -e 's/\n  [^ \n]+\n$/\n/' "$changelog_file"
 

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

	
 
    # @WORKAROUND: For using git tag signing on older versions of git.
 
    if [[ $(git -C "$base_dir" config --get tag.gpgSign) == true ]]; then
 
        local git_tag_gpgsign=("--sign")
 
    else
 
        local git_tag_gpgsign=()
 
    fi
 

	
 
    # 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 "${git_tag_gpgsign[@]}" -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.
 
    sed -i -e "s/$version/999.999.999/" "$info_file"
 
    changelog=$(cat <<EOF
 
---------------------------------------------------------------------------------------------------
 
Version: 999.999.999
 
Date: 9999-99-99
 
  Changes:
 
  Features:
 
  Bugfixes:
 
$(cat "$changelog_file")
 
EOF
 
                )
 
    echo "$changelog" > "$changelog_file"
 

	
 
    # Commit the changes.
 
    if ! git -C "$base_dir" add "$changelog_file" "$info_file" || \
 
       ! git -C "$base_dir" commit -m "Switched back to development version."; then
 
        error "Failed to create developement commit."
 
        return 1
 
    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 mod_name release_archive
 
    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
 
    mod_name=$(get_mod_name "$base_dir") || return 1
 
    version="${release_branch##release-}"
 
    release_archive="${base_dir}/dist/${mod_name}_${version}.zip"
 

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

	
 
    # Drop the release archive.
 
    if [[ -f "${base_dir}/dist/${mod_name}_${version}.zip" ]] &&
 
       ! rm "$release_archive"; then
 

	
 
        error "Failed to remove the release file: $release_archive"
 
        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)
 
    _TEXT_BLUE=$(tput setaf 6)
 
    _TEXT_GREEN=$(tput setaf 2)
 
    _TEXT_YELLOW=$(tput setaf 3)
 
    _TEXT_RED=$(tput setaf 1)
 
    _TEXT_RESET=$(tput sgr0)
 
else
 
    _TEXT_BOLD=""
 
    _TEXT_WHITE=""
 
    _TEXT_BLUE=""
 
    _TEXT_GREEN=""
 
    _TEXT_YELLOW=""
 
    _TEXT_RED=""
 
    _TEXT_RESET=""
 
fi
 

	
 
# Set-up functions for printing coloured messages.
 
function debug() {
 
    if [[ $DEBUG != 0 ]]; then
 
        echo "${_TEXT_BOLD}${_TEXT_BLUE}[DEBUG]${_TEXT_RESET}" "$@"
 
    fi
 
}
 

	
 
function info() {
 
    if [[ $QUIET == 0 ]]; then
 
        echo "${_TEXT_BOLD}${_TEXT_WHITE}[INFO] ${_TEXT_RESET}" "$@"
 
    fi
 
}
 

	
 
function success() {
 
    if [[ $QUIET == 0 ]]; then
 
        echo "${_TEXT_BOLD}${_TEXT_GREEN}[OK]   ${_TEXT_RESET}" "$@"
 
    fi
 
}
 

	
 
function warning() {
 
    echo "${_TEXT_BOLD}${_TEXT_YELLOW}[WARN] ${_TEXT_RESET}" "$@" >&2
 
}
 

	
 
function error() {
 
    echo "${_TEXT_BOLD}${_TEXT_RED}[ERROR]${_TEXT_RESET}" "$@" >&2
 
}
 

	
 
# Define error codes.
 
SUCCESS=0
 
ERROR_ARGUMENTS=1
 
ERROR_GENERAL=2
 

	
 
# Disable debug and quiet modes by default.
 
DEBUG=0
 
QUIET=0
 

	
 
# If no arguments were given, just show usage help.
 
if [[ -z ${1-} ]]; then
 
    short_help
 
    exit "$SUCCESS"
 
fi
 

	
 
# Parse the arguments
 
while getopts "qdvh" opt; do
 
    case "$opt" in
 
	q) QUIET=1;;
 
	d) DEBUG=1;;
 
        v) version
 
           exit "$SUCCESS";;
 
        h) long_help
 
           exit "$SUCCESS";;
 
        *) short_help
 
           exit "$ERROR_ARGUMENTS";;
 
    esac
 
done
 
i=$OPTIND
 
shift $(( i-1 ))
 

	
 
# Quiet and debug are mutually exclusive.
 
if [[ $QUIET != 0 && $DEBUG != 0 ]]; then
 
    error "Quiet and debug options are mutually exclusive."
 
    exit "$ERROR_ARGUMENTS"
 
fi
 

	
 
COMMAND="${1-}"
 
shift
 

	
 
if [[ $COMMAND == init ]]; then
 

	
 
    MOD_DIRECTORY_PATH="${1-}"
 
    shift
 

	
 
    if [[ -z $MOD_DIRECTORY_PATH ]]; then
0 comments (0 inline, 0 general) First comment
You need to be logged in to comment. Login now