Skip to content

Commit ed87f91

Browse files
committed
Initial commit
0 parents  commit ed87f91

12 files changed

+641
-0
lines changed

.devcontainer/devcontainer.json

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
2+
// https://github.com/microsoft/vscode-dev-containers/tree/v0.224.2/containers/alpine
3+
{
4+
"name": "texthtml/object-reaper",
5+
"build": {
6+
"dockerfile": "../.docker/Dockerfile",
7+
// Update 'VARIANT' to pick an Alpine version: 3.12, 3.13, 3.14, 3.15
8+
"args": { "VARIANT": "3.14" }
9+
},
10+
"workspaceMount": "source=${localWorkspaceFolder},target=/app,type=bind",
11+
"workspaceFolder": "/app",
12+
"remoteEnv": {
13+
"PATH": "${containerEnv:PATH}:/app/vendor/bin",
14+
"PROMPT_COMMAND": "short_pwd=$(sed \"s:\\([^/\\.]\\)[^/]*/:\\1/:g\" <<< ${PWD/#$HOME/\\~})",
15+
"PS1": "\\[\\e[0;35m\\]$short_pwd \\n\\[\\e[0;33m\\]$((( _ret_value )) && printf \"\\[\\e[0;31m\\]\")$\\[\\e[0m\\] ",
16+
"PS2": "\\[${_y}\\]❯ \\[${reset}\\]"
17+
},
18+
19+
"customizations": {
20+
"vscode": {
21+
22+
// Set *default* container specific settings.json values on container create.
23+
"settings": {},
24+
25+
// Add the IDs of extensions you want installed when the container is created.
26+
// Note that some extensions may not work in Alpine Linux. See https://aka.ms/vscode-remote/linux.
27+
"extensions": [
28+
"sleistner.vscode-fileutils",
29+
"britesnow.vscode-toggle-quotes",
30+
"xdebug.php-debug",
31+
"bmewburn.vscode-intelephense-client",
32+
"ikappas.phpcs",
33+
"ms-vscode.test-adapter-converter",
34+
"hbenl.vscode-test-explorer",
35+
"recca0120.vscode-phpunit",
36+
"Kasik96.latte",
37+
"getpsalm.psalm-vscode-plugin"
38+
]
39+
}
40+
},
41+
42+
// Use 'forwardPorts' to make a list of ports inside the container available locally.
43+
// "forwardPorts": [],
44+
45+
// Use 'postCreateCommand' to run commands after the container is created.
46+
// "postCreateCommand": "uname -a",
47+
48+
// Replace when using a ptrace-based debugger like C++, Go, and Rust
49+
// "runArgs": [ "--init", "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],
50+
51+
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
52+
"remoteUser": "dev"
53+
}

.docker/Dockerfile

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
FROM php:8.3
2+
3+
COPY dev.sh /tmp/library-scripts/
4+
5+
USER root
6+
7+
ARG USERNAME=dev
8+
ARG USER_UID=1000
9+
ARG USER_GID=${USER_UID}
10+
11+
RUN groupadd --gid ${USER_GID} ${USERNAME} && \
12+
useradd -s /bin/bash --uid ${USER_UID} --gid ${USERNAME} -m ${USERNAME}
13+
14+
COPY --from=composer:2.7.9 /usr/bin/composer /usr/bin/composer
15+
16+
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive && \
17+
bash /tmp/library-scripts/dev.sh "${USERNAME}"
18+
19+
RUN mkdir /app && chown ${USERNAME}: /app
20+
21+
WORKDIR /app
22+
23+
USER ${USERNAME}

.docker/dev.sh

+239
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
#!/usr/bin/env bash
2+
#-------------------------------------------------------------------------------------------------------------
3+
# Copyright (c) Microsoft Corporation. All rights reserved.
4+
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
5+
#-------------------------------------------------------------------------------------------------------------
6+
#
7+
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/common.md
8+
# Maintainer: The VS Code and Codespaces Teams
9+
#
10+
# Syntax: ./dev.sh [username]
11+
12+
set -e
13+
14+
USERNAME="$1"
15+
SCRIPT_DIR="$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)"
16+
MARKER_FILE="/usr/local/etc/vscode-dev-containers/common"
17+
18+
if [ "$(id -u)" -ne 0 ]; then
19+
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
20+
exit 1
21+
fi
22+
23+
# Ensure that login shells get the correct path if the user updated the PATH using ENV.
24+
rm -f /etc/profile.d/00-restore-env.sh
25+
echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh
26+
chmod +x /etc/profile.d/00-restore-env.sh
27+
28+
# Load markers to see which steps have already run
29+
if [ -f "${MARKER_FILE}" ]; then
30+
echo "Marker file found:"
31+
cat "${MARKER_FILE}"
32+
source "${MARKER_FILE}"
33+
fi
34+
35+
# Ensure apt is in non-interactive to avoid prompts
36+
export DEBIAN_FRONTEND=noninteractive
37+
38+
# Function to call apt-get if needed
39+
apt_get_update_if_needed()
40+
{
41+
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
42+
echo "Running apt-get update..."
43+
apt-get update
44+
else
45+
echo "Skipping apt-get update."
46+
fi
47+
}
48+
49+
# Run install apt-utils to avoid debconf warning then verify presence of other common developer tools and dependencies
50+
if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
51+
52+
package_list="apt-utils \
53+
sudo \
54+
gnupg2 \
55+
htop \
56+
curl \
57+
ca-certificates \
58+
less \
59+
jq \
60+
apt-transport-https \
61+
libc6 \
62+
libgcc1 \
63+
libkrb5-3 \
64+
libgssapi-krb5-2 \
65+
libicu[0-9][0-9] \
66+
liblttng-ust[0-9] \
67+
libstdc++6 \
68+
zlib1g \
69+
locales \
70+
init-system-helpers"
71+
72+
apt_get_update_if_needed
73+
74+
# Install libssl1.1 if available
75+
if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then
76+
package_list="${package_list} libssl1.1"
77+
fi
78+
79+
# Install appropriate version of libssl1.0.x if available
80+
libssl_package=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '')
81+
if [ "$(echo "$LIlibssl_packageBSSL" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then
82+
if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then
83+
# Debian 9
84+
package_list="${package_list} libssl1.0.2"
85+
elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then
86+
# Ubuntu 18.04, 16.04, earlier
87+
package_list="${package_list} libssl1.0.0"
88+
fi
89+
fi
90+
91+
echo "Packages to verify are installed: ${package_list}"
92+
apt-get -y install --no-install-recommends ${package_list} 2> >( grep -v 'debconf: delaying package configuration, since apt-utils is not installed' >&2 )
93+
94+
# Install git if not already installed (may be more recent than distro version)
95+
if ! type git > /dev/null 2>&1; then
96+
apt-get -y install --no-install-recommends git
97+
fi
98+
99+
PACKAGES_ALREADY_INSTALLED="true"
100+
fi
101+
102+
# Ensure at least the en_US.UTF-8 UTF-8 locale is available.
103+
104+
if [ "${LOCALE_ALREADY_SET}" != "true" ] && ! grep -o -E '^\s*en_US.UTF-8\s+UTF-8' /etc/locale.gen > /dev/null; then
105+
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
106+
locale-gen
107+
LOCALE_ALREADY_SET="true"
108+
fi
109+
110+
# Add add sudo support for non-root user
111+
if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then
112+
echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME
113+
chmod 0440 /etc/sudoers.d/$USERNAME
114+
EXISTING_NON_ROOT_USER="${USERNAME}"
115+
fi
116+
117+
# ** Shell customization section **
118+
if [ "${USERNAME}" = "root" ]; then
119+
user_rc_path="/root"
120+
else
121+
user_rc_path="/home/${USERNAME}"
122+
fi
123+
124+
# .bashrc snippet
125+
rc_snippet="$(cat << 'EOF'
126+
127+
if [ -z "${USER}" ]; then export USER=$(whoami); fi
128+
if [[ "${PATH}" != *"$HOME/.local/bin"* ]]; then export PATH="${PATH}:$HOME/.local/bin"; fi
129+
130+
# Display optional first run image specific notice if configured and terminal is interactive
131+
if [ -t 1 ] && [[ "${TERM_PROGRAM}" = "vscode" || "${TERM_PROGRAM}" = "codespaces" ]] && [ ! -f "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed" ]; then
132+
if [ -f "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" ]; then
133+
cat "/usr/local/etc/vscode-dev-containers/first-run-notice.txt"
134+
elif [ -f "/workspaces/.codespaces/shared/first-run-notice.txt" ]; then
135+
cat "/workspaces/.codespaces/shared/first-run-notice.txt"
136+
fi
137+
mkdir -p "$HOME/.config/vscode-dev-containers"
138+
# Mark first run notice as displayed after 10s to avoid problems with fast terminal refreshes hiding it
139+
((sleep 10s; touch "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed") &)
140+
fi
141+
142+
# Set the default git editor if not already set
143+
if [ -z "$(git config --get core.editor)" ] && [ -z "${GIT_EDITOR}" ]; then
144+
if [ "${TERM_PROGRAM}" = "vscode" ]; then
145+
if [[ -n $(command -v code-insiders) && -z $(command -v code) ]]; then
146+
export GIT_EDITOR="code-insiders --wait"
147+
else
148+
export GIT_EDITOR="code --wait"
149+
fi
150+
fi
151+
fi
152+
153+
EOF
154+
)"
155+
156+
# code shim, it fallbacks to code-insiders if code is not available
157+
cat << 'EOF' > /usr/local/bin/code
158+
#!/bin/sh
159+
160+
get_in_path_except_current() {
161+
which -a "$1" | grep -A1 "$0" | grep -v "$0"
162+
}
163+
164+
code="$(get_in_path_except_current code)"
165+
166+
if [ -n "$code" ]; then
167+
exec "$code" "$@"
168+
elif [ "$(command -v code-insiders)" ]; then
169+
exec code-insiders "$@"
170+
else
171+
echo "code or code-insiders is not installed" >&2
172+
exit 127
173+
fi
174+
EOF
175+
chmod +x /usr/local/bin/code
176+
177+
# systemctl shim - tells people to use 'service' if systemd is not running
178+
cat << 'EOF' > /usr/local/bin/systemctl
179+
#!/bin/sh
180+
set -e
181+
if [ -d "/run/systemd/system" ]; then
182+
exec /bin/systemctl/systemctl "$@"
183+
else
184+
echo '\n"systemd" is not running in this container due to its overhead.\nUse the "service" command to start services intead. e.g.: \n\nservice --status-all'
185+
fi
186+
EOF
187+
chmod +x /usr/local/bin/systemctl
188+
189+
codespaces_bash="$(cat \
190+
<<'EOF'
191+
192+
# Codespaces bash prompt theme
193+
__bash_prompt() {
194+
local userpart='`export XIT=$? \
195+
&& [ ! -z "${GITHUB_USER}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER} " || echo -n "\[\033[0;32m\]\u " \
196+
&& [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`'
197+
local gitbranch='`\
198+
if [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \
199+
export BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD 2>/dev/null); \
200+
if [ "${BRANCH}" != "" ]; then \
201+
echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH}" \
202+
&& if git ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \
203+
echo -n " \[\033[1;33m\]✗"; \
204+
fi \
205+
&& echo -n "\[\033[0;36m\]) "; \
206+
fi; \
207+
fi`'
208+
local lightblue='\[\033[1;34m\]'
209+
local removecolor='\[\033[0m\]'
210+
PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ "
211+
unset -f __bash_prompt
212+
}
213+
__bash_prompt
214+
215+
EOF
216+
)"
217+
218+
# Add RC snippet and custom bash prompt
219+
if [ "${RC_SNIPPET_ALREADY_ADDED}" != "true" ]; then
220+
echo "${rc_snippet}" >> /etc/bash.bashrc
221+
# echo "${codespaces_bash}" >> "${user_rc_path}/.bashrc"
222+
# echo 'export PROMPT_DIRTRIM=4' >> "${user_rc_path}/.bashrc"
223+
# if [ "${USERNAME}" != "root" ]; then
224+
# echo "${codespaces_bash}" >> "/root/.bashrc"
225+
# echo 'export PROMPT_DIRTRIM=4' >> "/root/.bashrc"
226+
# fi
227+
# chown ${USERNAME}:${group_name} "${user_rc_path}/.bashrc"
228+
RC_SNIPPET_ALREADY_ADDED="true"
229+
fi
230+
231+
# Write marker file
232+
mkdir -p "$(dirname "${MARKER_FILE}")"
233+
echo -e "\
234+
PACKAGES_ALREADY_INSTALLED=${PACKAGES_ALREADY_INSTALLED}\n\
235+
LOCALE_ALREADY_SET=${LOCALE_ALREADY_SET}\n\
236+
EXISTING_NON_ROOT_USER=${EXISTING_NON_ROOT_USER}\n\
237+
RC_SNIPPET_ALREADY_ADDED=${RC_SNIPPET_ALREADY_ADDED}" > "${MARKER_FILE}"
238+
239+
echo "Done!"

.gitattributes

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/.devcontainer export-ignore
2+
/.docker export-ignore
3+
/.github export-ignore
4+
/composer.lock export-ignore
5+
/phpcs.xml.dist export-ignore
6+
/phpstan.neon.dist export-ignore

.github/workflows/test.yml

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
pull_request:
7+
branches: [ "main" ]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
build:
14+
15+
runs-on: ubuntu-latest
16+
17+
strategy:
18+
matrix:
19+
php-versions: ['8.1', '8.2', '8.3']
20+
21+
steps:
22+
- uses: actions/checkout@v3
23+
24+
- name: Setup PHP
25+
uses: shivammathur/setup-php@v2
26+
with:
27+
php-version: ${{ matrix.php-versions }}
28+
ini-values: zend.assertions=1, assert.exception=1
29+
30+
- name: Validate composer.json
31+
run: composer validate --strict
32+
33+
- name: Cache Composer packages
34+
id: composer-cache
35+
uses: actions/cache@v3
36+
with:
37+
path: vendor
38+
key: ${{ runner.os }}-php-${{ matrix.php-versions }}-${{ hashFiles('composer.json') }}
39+
restore-keys: |
40+
${{ runner.os }}-php-${{ matrix.php-versions }}
41+
42+
- name: Install dependencies
43+
run: composer install --prefer-dist --no-progress
44+
45+
- name: Run the doc tests
46+
run: vendor/bin/doctest
47+
48+
- name: Run linter
49+
run: vendor/bin/phpcs -ps
50+
51+
- name: Run static analysis (PHPStan)
52+
run: vendor/bin/phpstan

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/vendor/
2+
/composer.lock

0 commit comments

Comments
 (0)