Skip to content

Commit 679ed14

Browse files
[#110] Added init script to make onboarding easier (#132)
Co-authored-by: Alex Skrypnyk <alex@drevops.com>
1 parent 0333c85 commit 679ed14

13 files changed

+801
-88
lines changed

.github/workflows/test-scaffold.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,37 @@ jobs:
2020
- name: Checkout code
2121
uses: actions/checkout@v4
2222

23+
- name: Setup PHP
24+
uses: shivammathur/setup-php@v2
25+
2326
- name: Check coding standards
2427
uses: luizm/action-sh-checker@v0.8.0
2528
env:
2629
SHFMT_OPTS: -i 2 -ci -s -d
30+
31+
- name: Setup Node.js
32+
uses: actions/setup-node@v4
33+
34+
- name: Setup kcov
35+
run: wget https://github.com/SimonKagstrom/kcov/releases/download/v42/kcov-amd64.tar.gz && tar -xf kcov-amd64.tar.gz && sudo mv ./usr/local/bin/kcov /usr/local/bin/kcov && kcov --version
36+
37+
- name: Install dependencies
38+
run: npm ci
39+
working-directory: .scaffold/tests
40+
41+
- name: Run tests
42+
run: kcov --include-pattern=.sh,.bash --bash-parse-files-in-dir=. --exclude-pattern=vendor,node_modules,.scaffold-coverage-html "$(pwd)"/.scaffold-coverage-html .scaffold/tests/node_modules/.bin/bats .scaffold/tests/bats
43+
44+
- name: Upload coverage report as an artifact
45+
uses: actions/upload-artifact@v4
46+
with:
47+
name: ${{github.job}}-code-coverage-report
48+
path: ./.scaffold-coverage-html
49+
if-no-files-found: error
50+
51+
# - name: Upload coverage report to Codecov
52+
# uses: codecov/codecov-action@v4
53+
# with:
54+
# directory: ./.scaffold-coverage-html
55+
# fail_ci_if_error: true
56+
# token: ${{ secrets.CODECOV_TOKEN }}

.scaffold/tests/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/node_modules
2+
/coverage
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Scaffold template assertions.
4+
#
5+
6+
# This file structure should exist in every project type.
7+
assert_files_present_common() {
8+
local dir="${1:-$(pwd)}"
9+
10+
pushd "${dir}" >/dev/null || exit 1
11+
12+
# Assert that some files must be exist.
13+
assert_file_exists "force_crystal.info.yml"
14+
assert_file_exists "phpcs.xml"
15+
assert_file_exists "phpmd.xml"
16+
assert_file_exists "phpstan.neon"
17+
assert_file_exists ".editorconfig"
18+
assert_file_exists ".gitattributes"
19+
assert_file_exists ".gitignore"
20+
assert_file_exists "README.md"
21+
assert_file_exists "logo.png"
22+
23+
# Assert that some files must not be exist.
24+
assert_file_not_exists "README.dist.md"
25+
assert_file_not_exists "logo.tmp.png"
26+
assert_file_not_exists "LICENSE"
27+
assert_file_not_exists ".github/workflows/test-scaffold.yml"
28+
29+
# Assert some dirs/files must not be exist.
30+
assert_dir_not_exists ".scaffold"
31+
32+
# Assert that .gitignore were processed correctly.
33+
assert_file_contains ".gitignore" "composer.lock"
34+
assert_file_contains ".gitignore" "build"
35+
assert_file_not_contains ".gitignore" "/coverage"
36+
37+
# Assert that documentation was processed correctly.
38+
assert_file_not_contains README.md "META"
39+
40+
# Assert that .gitattributes were processed correctly.
41+
assert_file_contains ".gitattributes" ".editorconfig"
42+
assert_file_not_contains ".gitattributes" "# .editorconfig"
43+
assert_file_contains ".gitattributes" ".gitattributes"
44+
assert_file_not_contains ".gitattributes" "# .gitattributes"
45+
assert_file_contains ".gitattributes" ".github"
46+
assert_file_not_contains ".gitattributes" "# .github"
47+
assert_file_contains ".gitattributes" ".gitignore"
48+
assert_file_not_contains ".gitattributes" "# .gitignore"
49+
assert_file_not_contains ".gitattributes" "# Uncomment the lines below in your project."
50+
assert_file_contains ".gitattributes" "tests"
51+
assert_file_contains ".gitattributes" "phpcs.xml"
52+
assert_file_contains ".gitattributes" "phpmd.xml"
53+
assert_file_contains ".gitattributes" "phpstan.neon"
54+
assert_file_not_contains ".gitattributes" "# tests"
55+
assert_file_not_contains ".gitattributes" "# phpcs.xml"
56+
assert_file_not_contains ".gitattributes" "# phpmd.xml"
57+
assert_file_not_contains ".gitattributes" "# phpstan.neon"
58+
59+
# Assert that composer.json were processed correctly.
60+
assert_file_contains "composer.json" '"name": "drupal/force_crystal"'
61+
assert_file_contains "composer.json" '"description": "Provides force_crystal functionality."'
62+
assert_file_contains "composer.json" '"homepage": "https://drupal.org/project/force_crystal"'
63+
assert_file_contains "composer.json" '"issues": "https://drupal.org/project/issues/force_crystal"'
64+
assert_file_contains "composer.json" '"source": "https://git.drupalcode.org/project/force_crystal"'
65+
66+
# Assert that extension info file were processed correctly.
67+
assert_file_contains "force_crystal.info.yml" 'name: Force Crystal'
68+
69+
# Assert other things.
70+
assert_dir_not_contains_string "${dir}" "your_extension"
71+
assert_dir_contains_string "${dir}" "YodasHut"
72+
73+
popd >/dev/null || exit 1
74+
}
75+
76+
assert_files_present_extension_type_module() {
77+
local dir="${1:-$(pwd)}"
78+
79+
pushd "${dir}" >/dev/null || exit 1
80+
81+
# Assert that extension info file were processed correctly.
82+
assert_file_contains "force_crystal.info.yml" 'type: module'
83+
assert_file_not_contains "force_crystal.info.yml" 'type: theme'
84+
assert_file_not_contains "force_crystal.info.yml" 'base theme: false'
85+
86+
# Assert that composer.json file were processed correctly.
87+
assert_file_contains "composer.json" '"type": "drupal-module"'
88+
89+
# Assert some dirs/files must be exist.
90+
assert_dir_exists "tests/src/Unit"
91+
assert_dir_exists "tests/src/Functional"
92+
93+
popd >/dev/null || exit 1
94+
}
95+
96+
assert_files_present_extension_type_theme() {
97+
local dir="${1:-$(pwd)}"
98+
99+
pushd "${dir}" >/dev/null || exit 1
100+
101+
# Assert that extension info file were processed correctly.
102+
assert_file_contains "force_crystal.info.yml" 'type: theme'
103+
assert_file_contains "force_crystal.info.yml" 'base theme: false'
104+
assert_file_not_contains "force_crystal.info.yml" 'type: module'
105+
106+
# Assert that composer.json file were processed correctly.
107+
assert_file_contains "composer.json" '"type": "drupal-theme"'
108+
109+
# Assert some dirs/files must not be exist.
110+
assert_dir_not_exists "tests/src/Unit"
111+
assert_dir_not_exists "tests/src/Functional"
112+
113+
popd >/dev/null || exit 1
114+
}
115+
116+
assert_workflow() {
117+
local dir="${1:-$(pwd)}"
118+
119+
pushd "${dir}" >/dev/null || exit 1
120+
121+
./.devtools/build-codebase.sh
122+
123+
# Lint.
124+
pushd "build" >/dev/null || exit 1
125+
vendor/bin/phpcs
126+
vendor/bin/phpstan
127+
vendor/bin/rector --clear-cache --dry-run
128+
vendor/bin/phpmd . text phpmd.xml
129+
vendor/bin/twigcs
130+
popd >/dev/null || exit 1
131+
132+
# Change mode to make bats have enough permission to clean tmp test directory.
133+
chmod -R 777 "build/web/sites/default"
134+
135+
popd >/dev/null || exit 1
136+
}

.scaffold/tests/bats/_helper.bash

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Helpers related to common testing functionality.
4+
#
5+
# Run with "--verbose-run" to see debug output.
6+
#
7+
8+
################################################################################
9+
# BATS HOOK IMPLEMENTATIONS #
10+
################################################################################
11+
12+
setup() {
13+
[ ! -d ".git" ] && echo "Tests must be run from the repository root directory." && exit 1
14+
15+
# For a list of available variables see:
16+
# @see https://bats-core.readthedocs.io/en/stable/writing-tests.html#special-variables
17+
18+
# Register a path to libraries.
19+
export BATS_LIB_PATH="${BATS_TEST_DIRNAME}/../node_modules"
20+
21+
# Load 'bats-helpers' library.
22+
bats_load_library bats-helpers
23+
24+
# Setup command mocking.
25+
setup_mock
26+
27+
# Current directory where the test is run from.
28+
# shellcheck disable=SC2155
29+
export CUR_DIR="$(pwd)"
30+
31+
# Project directory root (where .git is located).
32+
export ROOT_DIR="${CUR_DIR}"
33+
34+
# Directory where the shell command script will be running in.
35+
export BUILD_DIR="${BUILD_DIR:-"${BATS_TEST_TMPDIR//\/\//\/}/scaffold-$(date +%s)"}"
36+
fixture_prepare_dir "${BUILD_DIR}"
37+
38+
# Copy codebase at the last commit into the BUILD_DIR.
39+
# Tests requiring to work with the copy of the codebase should opt-in using
40+
# BATS_FIXTURE_EXPORT_CODEBASE_ENABLED=1.
41+
# Note that during development of tests the local changes need to be
42+
# committed.
43+
fixture_export_codebase "${BUILD_DIR}" "${ROOT_DIR}"
44+
45+
# Print debug information if "--verbose-run" is passed.
46+
# LCOV_EXCL_START
47+
if [ "${BATS_VERBOSE_RUN-}" = "1" ]; then
48+
echo "BUILD_DIR: ${BUILD_DIR}" >&3
49+
fi
50+
# LCOV_EXCL_END
51+
52+
# Change directory to the current project directory for each test. Tests
53+
# requiring to operate outside of BUILD_DIR should change directory explicitly
54+
# within their tests.
55+
pushd "${BUILD_DIR}" >/dev/null || exit 1
56+
}
57+
58+
teardown() {
59+
# Move back to the original directory.
60+
popd >/dev/null || cd "${CUR_DIR}" || exit 1
61+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/usr/bin/env bats
2+
#
3+
# Functional tests for init.sh.
4+
#
5+
# Example usage:
6+
# ./.scaffold/tests/node_modules/.bin/bats --no-tempdir-cleanup --formatter tap --filter-tags smoke .scaffold/tests
7+
#
8+
# shellcheck disable=SC2030,SC2031,SC2129
9+
10+
load _helper
11+
load _assert_init
12+
13+
export BATS_FIXTURE_EXPORT_CODEBASE_ENABLED=1
14+
export SCRIPT_FILE="init.sh"
15+
16+
# bats test_tags=smoke
17+
@test "Init, defaults - extension module, workflow" {
18+
answers=(
19+
"YodasHut" # namespace
20+
"Force Crystal" # name
21+
"force_crystal" # machine_name
22+
"module" # type
23+
"GitHub Actions" # ci_provider
24+
"nothing" # remove init script
25+
"nothing" # proceed with init
26+
)
27+
tui_run "${answers[@]}"
28+
29+
assert_output_contains "Please follow the prompts to adjust your extension configuration"
30+
assert_files_present_common "${BUILD_DIR}"
31+
assert_files_present_extension_type_module "${BUILD_DIR}"
32+
assert_file_not_exists ".circleci/config.yml"
33+
assert_output_contains "Initialization complete."
34+
35+
assert_workflow "${BUILD_DIR}"
36+
}
37+
38+
# bats test_tags=smoke
39+
@test "Init, extension theme, workflow" {
40+
answers=(
41+
"YodasHut" # namespace
42+
"Force Crystal" # name
43+
"force_crystal" # machine_name
44+
"theme" # type
45+
"GitHub Actions" # ci_provider
46+
"nothing" # remove init script
47+
"nothing" # proceed with init
48+
)
49+
tui_run "${answers[@]}"
50+
51+
assert_output_contains "Please follow the prompts to adjust your extension configuration"
52+
assert_files_present_common "${BUILD_DIR}"
53+
assert_files_present_extension_type_theme "${BUILD_DIR}"
54+
assert_file_not_exists ".circleci/config.yml"
55+
assert_output_contains "Initialization complete."
56+
57+
assert_workflow "${BUILD_DIR}"
58+
}
59+
60+
# bats test_tags=smoke
61+
@test "Init, CircleCI" {
62+
answers=(
63+
"YodasHut" # namespace
64+
"Force Crystal" # name
65+
"force_crystal" # machine_name
66+
"module" # type
67+
"CircleCI" # ci_provider
68+
"nothing" # remove init script
69+
"nothing" # proceed with init
70+
)
71+
tui_run "${answers[@]}"
72+
73+
assert_output_contains "Please follow the prompts to adjust your extension configuration"
74+
assert_files_present_common "${BUILD_DIR}"
75+
assert_files_present_extension_type_module "${BUILD_DIR}"
76+
assert_file_exists ".circleci/config.yml"
77+
assert_dir_not_exists ".github/workflows"
78+
assert_output_contains "Initialization complete."
79+
}
80+
81+
@test "Init, do not remove script" {
82+
answers=(
83+
"YodasHut" # namespace
84+
"Force Crystal" # name
85+
"force_crystal" # machine_name
86+
"module" # type
87+
"CircleCI" # ci_provider
88+
"n" # remove init script
89+
"nothing" # proceed with init
90+
)
91+
tui_run "${answers[@]}"
92+
93+
assert_output_contains "Please follow the prompts to adjust your extension configuration"
94+
assert_files_present_common "${BUILD_DIR}"
95+
assert_files_present_extension_type_module "${BUILD_DIR}"
96+
assert_file_exists "init.sh"
97+
assert_output_contains "Initialization complete."
98+
}
99+
100+
@test "Init, remove script" {
101+
answers=(
102+
"YodasHut" # namespace
103+
"Force Crystal" # name
104+
"force_crystal" # machine_name
105+
"module" # type
106+
"CircleCI" # ci_provider
107+
"y" # remove init script
108+
"nothing" # proceed with init
109+
)
110+
tui_run "${answers[@]}"
111+
112+
assert_output_contains "Please follow the prompts to adjust your extension configuration"
113+
assert_files_present_common "${BUILD_DIR}"
114+
assert_files_present_extension_type_module "${BUILD_DIR}"
115+
assert_file_not_exists "init.sh"
116+
assert_output_contains "Initialization complete."
117+
}

.scaffold/tests/bats/smoke.bats

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env bats
2+
#
3+
# Smoke tests.
4+
#
5+
# shellcheck disable=SC2030,SC2031,SC2129
6+
7+
load _helper
8+
9+
# ./tests/scaffold/node_modules/.bin/bats --no-tempdir-cleanup --formatter tap --filter-tags smoke tests/scaffold
10+
# bats test_tags=smoke
11+
@test "Smoke" {
12+
assert_contains "scaffold" "${BUILD_DIR}"
13+
}

.scaffold/tests/bats/unit.init.bats

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env bats
2+
#
3+
# Unit tests for init.sh.
4+
#
5+
# shellcheck disable=SC2034
6+
7+
load _helper
8+
load "../../../init.sh"
9+
10+
@test "Test all conversions" {
11+
input="I am a_string-With spaces 13"
12+
13+
TEST_CASES=(
14+
"$input" "file_name" "i_am_a_string-with_spaces_13"
15+
"$input" "route_path" "i_am_a_string-with_spaces_13"
16+
)
17+
18+
dataprovider_run "convert_string" 3
19+
}

0 commit comments

Comments
 (0)