-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
45c6725
commit 1fa2646
Showing
24 changed files
with
1,175 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#!/bin/bash | ||
# @name checks | ||
# @deps utils/boolean | ||
# @brief A package for checks and validations. | ||
|
||
set -euo pipefail | ||
|
||
source 'src/first_time_setup/utils/boolean.sh' | ||
|
||
# @description Check if the script should run in non-interactive mode. | ||
# @arg $1 The jurisdiction name. | ||
# @arg $2 The repository URL. | ||
is::interactive() { | ||
[[ -z ${1:-} || -z ${2:-} ]] && echo true || echo false | ||
} | ||
|
||
# @description Check if the script is running in a CI environment. | ||
# @arg $1 The CI environment variable. | ||
is::ci() { | ||
is::true "${1:-}" | ||
} | ||
|
||
# @description Check if the repository exists. | ||
is::repo() { | ||
git rev-parse --is-inside-work-tree &>/dev/null && echo true || echo false | ||
} | ||
|
||
# @description Check if the setup should persevere. | ||
# @arg $1 If we are in a CI environment. | ||
# @arg $2 If the repository exists. | ||
setup::persevere() { | ||
local -r is_ci=$(is::true "${1:-}") | ||
local -r is_repo=$(is::true "${2:-}") | ||
if ! "${is_ci}" && "${is_repo}"; then echo false; else echo true; fi | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
#!/bin/bash | ||
# @name envvars | ||
# @deps none | ||
# @brief A package for setting the environment variables. | ||
|
||
set -euo pipefail | ||
|
||
if [[ -z ${JURISDICTION_NAME+A} ]]; then | ||
readonly JURISDICTION_NAME="${JURISDICTION_NAME:-}" | ||
fi | ||
|
||
if [[ -z ${REPOSITORY_URL+A} ]]; then | ||
readonly REPOSITORY_URL="${REPOSITORY_URL:-}" | ||
fi | ||
|
||
if [[ -z ${CI+A} ]]; then | ||
readonly CI="${CI:-}" | ||
fi | ||
|
||
if [[ -z ${DRY_MODE+A} ]]; then | ||
readonly DRY_MODE="${DRY_MODE:-}" | ||
fi | ||
|
||
if [[ -z ${SCRIPT_PATH+A} ]]; then | ||
readonly SCRIPT_PATH=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) | ||
fi | ||
|
||
if [[ -z ${DEV_MODE+A} ]]; then | ||
if [[ -f "${SCRIPT_PATH}/README.md" ]]; then | ||
readonly DEV_MODE='false' | ||
else | ||
readonly DEV_MODE='true' | ||
fi | ||
fi | ||
|
||
if [[ -z ${ROOT_PATH+A} ]]; then | ||
if ${DEV_MODE}; then | ||
readonly ROOT_PATH=$(cd "${SCRIPT_PATH}/../.." && pwd) | ||
else | ||
readonly ROOT_PATH=${SCRIPT_PATH} | ||
fi | ||
fi | ||
|
||
if [[ -z ${ROOT_DIR+A} ]]; then | ||
readonly ROOT_DIR=${ROOT_PATH##*/} | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
#!/bin/bash | ||
# @name main | ||
# @deps checks envvars messages setup status utils/* | ||
# @brief Setup a new OpenFisca extension package. | ||
|
||
source 'src/first_time_setup/utils/boolean.sh' | ||
source 'src/first_time_setup/utils/colours.sh' | ||
source 'src/first_time_setup/utils/file.sh' | ||
source 'src/first_time_setup/utils/string.sh' | ||
source 'src/first_time_setup/utils/subshell.sh' | ||
source 'src/first_time_setup/utils/url.sh' | ||
source 'src/first_time_setup/checks.sh' | ||
source 'src/first_time_setup/envvars.sh' | ||
source 'src/first_time_setup/messages.sh' | ||
source 'src/first_time_setup/setup.sh' | ||
source 'src/first_time_setup/status.sh' | ||
|
||
# @description User interruption. | ||
# @internal | ||
main.trap.interrupted() { | ||
local -r exit_code=$? | ||
trap - SIGINT | ||
echo '' | ||
echo -e "$(colour::warn 'Interrupted')" >&2 | ||
exit "${exit_code}" | ||
} | ||
|
||
# @description Cleanup on exit. | ||
# @internal | ||
main.trap.cleanup() { | ||
local exit_code=$? | ||
trap - EXIT | ||
echo -e "$(colour::info 'Exiting, bye!')" | ||
exit "${exit_code}" | ||
} | ||
|
||
# @description Generic error message. | ||
# @arg $1 The message to display. | ||
# @internal | ||
main.error() { | ||
local -r message="${1}" | ||
echo -e "$(colour::fail "${message}")" >&2 | ||
} | ||
|
||
# @description Main function to drive the script. | ||
main() { | ||
# Exit immediately if a command exits with a non-zero status. | ||
set -o errexit | ||
# Ensure that the ERR trap is inherited by shell functions. | ||
set -o errtrace | ||
# More verbosity when something within a function fails. | ||
set -o functrace | ||
# Treat unset variables as an error and exit immediately. | ||
set -o nounset | ||
# Prevent errors in a pipeline from being masked. | ||
set -o pipefail | ||
# Make word splitting happen only on newlines and tab characters. | ||
IFS=$'\n\t' | ||
|
||
# Define a cleanup functions to be called on script exit or interruption. | ||
trap main.trap.interrupted SIGINT | ||
trap main.trap.cleanup EXIT | ||
|
||
# Make sure we are not being sourced. Exit if it is the case. | ||
if "$(is::sourced)"; then | ||
main.error 'This script should not be sourced but executed directly' | ||
exit 1 | ||
fi | ||
|
||
# Support being called from anywhere on the file system. | ||
cd "${ROOT_PATH}" | ||
|
||
# Define the variables we will use. | ||
local name="${JURISDICTION_NAME}" | ||
local url="${REPOSITORY_URL}" | ||
local -r interactive=$(is::interactive "${name}" "${url}") | ||
local -r ci=$(is::ci "${CI}") | ||
local -r repo=$(is::repo) | ||
local -r persevere="$(setup::persevere "${ci}" "${repo}")" | ||
local -r dry=$(is::true "${DRY_MODE}") | ||
local -r module='openfisca_extension_template' | ||
local -r first_commit='Initial import from OpenFisca-Extension_Template' | ||
local -r second_commit='Customise extension_template through script' | ||
|
||
# Check if we can continue. | ||
colour::info "$(msg::welcome)" | ||
status::gather_info "${name}" "${url}" "${interactive}" | ||
status::check_continue "${ci}" "${repo}" "${persevere}" "${dry}" | ||
if ! "${persevere}" && ! "${dry}"; then | ||
echo '' | ||
main.error "$(msg::stop)" | ||
echo '' | ||
exit 2 | ||
fi | ||
|
||
echo '' | ||
colour::task 'We will now start setting up your new package' | ||
|
||
# Process the jurisdiction name. | ||
if [[ -z ${name} ]]; then echo ''; fi | ||
while [[ -z ${name} ]]; do | ||
echo -e -n "$(colour::user "$(msg::prompt_name)")" | ||
IFS= read -r -p ' ' name | ||
done | ||
readonly name | ||
local -r label=$(setup::name_label "${name}") | ||
local -r snake=$(setup::name_snake "${label}") | ||
|
||
# Process the repository URL. | ||
if [[ -z ${url} ]]; then echo ''; fi | ||
while [[ -z ${url} ]]; do | ||
echo -e -n "$(colour::user "$(msg::prompt_url)")" | ||
IFS= read -r -p ' ' url | ||
done | ||
readonly url | ||
local -r folder=$(setup::repository_folder "${url}") | ||
|
||
status::pre_summary "${name}" "${snake}" "${url}" | ||
|
||
# Shall we proceed? | ||
echo '' | ||
local continue=$(is::false "${interactive}") | ||
local prompt=$(colour::user "$(msg::prompt_continue)") | ||
if "${continue}"; then echo -e "${prompt} Y"; fi | ||
while ! "${continue}"; do | ||
echo -e -n "${prompt}" | ||
IFS= read -r -p ' ' continue | ||
continue=$(is::true "${continue}") | ||
if ! "${continue}"; then break; fi | ||
done | ||
unset prompt | ||
readonly continue | ||
echo -e "$(colour::logs "${continue}")" | ||
if ! "${continue}"; then echo '' && exit 3; fi | ||
|
||
echo '' | ||
colour::task 'Now we can proceed with the setup' | ||
|
||
local -r package="openfisca_${snake}" | ||
local -r lineno_readme=$(setup::readme_lineno) | ||
if [[ ${lineno_readme} -eq -1 ]]; then | ||
echo '' | ||
main.error 'Could not find the last line number of the README.md section' | ||
echo '' | ||
exit 4 | ||
fi | ||
local -r lineno_changelog=$(setup::changelog_lineno) | ||
if [[ ${lineno_changelog} -eq -1 ]]; then | ||
echo '' | ||
main.error 'Could not find the last line number of the CHANGELOG.md section' | ||
echo '' | ||
exit 5 | ||
fi | ||
|
||
# Initialise the repository. | ||
if ! "${ci}" || "${dry}"; then | ||
echo '' | ||
colour::pass 'Initialise git repository...' | ||
if ! "${dry}"; then | ||
setup::init_repository "${ROOT_DIR}" "${label}" "${first_commit}" | ||
else | ||
colour::warn 'Skipping git repository initialisation because of dry run' | ||
fi | ||
colour::pass "Commit made to 'main' with message:" | ||
colour::logs "${first_commit}" | ||
fi | ||
|
||
# And go on... | ||
colour::pass 'Replace default extension_template references' | ||
local -r files=$(git ls-files "src/${module}") | ||
setup::replace_references "${label}" "${snake}" "${name}" "${files}" | ||
colour::pass 'Remove bootstrap instructions' | ||
setup::remove_bootstrap_instructions "${lineno_readme}" | ||
colour::pass 'Prepare README.md and CONTRIBUTING.md' | ||
setup::prepare_readme_contributing "${url}" | ||
colour::pass 'Prepare CHANGELOG.md' | ||
setup::prepare_changelog "${lineno_changelog}" | ||
colour::pass 'Prepare pyproject.toml' | ||
setup::prepare_pyproject "${url}" "${folder}" | ||
colour::pass 'Rename package to:' | ||
colour::logs "${package}" | ||
if ! "${dry}"; then | ||
setup::rename_package "${package}" | ||
else | ||
colour::warn 'Skipping renaming of package because of dry run' | ||
fi | ||
colour::pass 'Remove single use first time setup files' | ||
if ! "${dry}"; then | ||
setup::remove_files | ||
else | ||
colour::warn 'Skipping removal of first time setup files because of dry run' | ||
fi | ||
|
||
# Committing and tagging take directly place in the GitHub Actions workflow. | ||
if "${ci}"; then | ||
echo '' | ||
colour::done "$(msg::goodbye)" | ||
echo '' | ||
exit 0 | ||
fi | ||
|
||
# Second commit and first tag. | ||
colour::pass 'Committing and tagging...' | ||
if ! "${dry}"; then | ||
setup::second_commit "${second_commit}" | ||
else | ||
colour::warn 'Skipping committing and tagging because of dry run' | ||
fi | ||
colour::pass "Second commit and first tag made on 'main' branch:" | ||
colour::logs "${second_commit}" | ||
|
||
# And finish! :) | ||
echo '' | ||
colour::done "$(msg::byebye "${label}")" | ||
echo '' | ||
} | ||
|
||
main "$@" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
#!/bin/bash | ||
# @name messages | ||
# @deps envvars | ||
# @brief A package for setting the messages used by the setup script. | ||
|
||
set -euo pipefail | ||
|
||
source 'src/first_time_setup/envvars.sh' | ||
|
||
# @internal | ||
msg.version() { | ||
grep '^version =' pyproject.toml | cut -d '"' -f 2 | ||
} | ||
|
||
# @description Define the welcome message. | ||
msg::welcome() { | ||
local version | ||
version=$(msg.version) | ||
cat <<MSG | ||
Welcome to the OpenFisca Extension Template setup script v${version}! | ||
This script will guide you through the process of setting up a new OpenFisca | ||
jurisdiction from start to finish. We will begin now... | ||
MSG | ||
} | ||
|
||
# @description Define the ci/repo validation message. | ||
msg::stop() { | ||
cat <<MSG | ||
It seems you cloned this repository, or already initialised it. Refusing to go | ||
further as you might lose work. If you are certain this is a new repository, | ||
run 'cd "${ROOT_PATH}" && rm -rf .git' to erase the history. | ||
MSG | ||
} | ||
|
||
# @description Define the prompt for the jurisdiction name. | ||
msg::prompt_name() { | ||
cat <<MSG | ||
The name of the jurisdiction (usually a city or a region, e.g. Île-d'Yeu, | ||
Val-d'Isère...) you will model the rules of: | ||
MSG | ||
} | ||
|
||
# @description Define the prompt for the url of the repository. | ||
msg::prompt_url() { | ||
cat <<MSG | ||
Your Git repository URL (i.e. | ||
https://githost.example/organisation/openfisca-jurisdiction): | ||
MSG | ||
} | ||
|
||
# @description Define the message whether to continue or not. | ||
msg::prompt_continue() { | ||
cat <<MSG | ||
Would you like to continue (type Y for yes, N for no): | ||
MSG | ||
} | ||
|
||
# @description Define the good bye message. | ||
msg::goodbye() { | ||
cat <<MSG | ||
The setup script has finished. You can now start writing your legislation with | ||
OpenFisca 🎉. Happy rules-as-coding! | ||
MSG | ||
} | ||
|
||
# @description Define the byebye message. | ||
# @arg $1 The jurisdiction label. | ||
msg::byebye() { | ||
cat <<MSG | ||
Bootstrap complete, you can now push this codebase to your remote repository. | ||
First, set up the remote with 'git remote add origin <SSH repository URL>'. | ||
You can then 'git push origin main' and refer to the README.md. | ||
The parent directory name has been changed, you can use | ||
'cd ../openfisca-${1} to navigate to it. | ||
MSG | ||
} |
Oops, something went wrong.