Skip to content

Commit 0e58493

Browse files
authored
Initial commit
0 parents  commit 0e58493

32 files changed

+3051
-0
lines changed

.devcontainer/devcontainer.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"image": "mcr.microsoft.com/devcontainers/base:alpine-3.20",
3+
4+
"customizations": {
5+
"vscode": {
6+
"extensions": ["ms-vscode.live-server"],
7+
"settings": {
8+
// Hide workspace files to make it seem like a blank working environment
9+
"files.exclude": {
10+
"**/.git": true,
11+
"**/.codespaces": true,
12+
"**/exercise-monitor.log": true,
13+
// This variable is not dynamic. It is replaced by workflow 0-start-exercise.yml
14+
"**/${RepoName}": true
15+
},
16+
17+
"livePreview.openPreviewTarget": "External Browser",
18+
"livePreview.serverRoot": "stack-overflown/src",
19+
20+
// Hide publish button
21+
"git.showActionButton": {
22+
"publish": false
23+
},
24+
25+
// Don't show notification when devcontainer.json is removed
26+
"github.codespaces.devcontainerChangedNotificationStyle": "none",
27+
28+
// Show everything for Git graph
29+
"scm.graph.showIncomingChanges": true,
30+
"scm.graph.showOutgoingChanges": true,
31+
"scm.defaultViewMode": "tree",
32+
"scm.graph.badges": "all"
33+
}
34+
}
35+
},
36+
37+
"workspaceFolder": "/workspaces",
38+
39+
"postCreateCommand": "./${RepositoryName}/.devcontainer/post-create.sh",
40+
"postStartCommand": "./${RepositoryName}/.devcontainer/post-start.sh"
41+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/bin/bash
2+
3+
echo "Git Hook: Post Checkout"
4+
5+
# Get checkout information
6+
PREVIOUS_HEAD=$1
7+
NEW_HEAD=$2
8+
BRANCH_NAME=$(git branch --show-current)
9+
REPO_NAME=$(basename "$(git rev-parse --show-toplevel)")
10+
11+
# Send repository dispatch event
12+
curl -X POST \
13+
-H "Accept: application/vnd.github.v3+json" \
14+
-H "Authorization: token ${GITHUB_TOKEN}" \
15+
"https://api.github.com/repos/${GITHUB_REPOSITORY}/dispatches" \
16+
-d '{
17+
"event_type": "post-checkout",
18+
"client_payload": {
19+
"previous_head": "'"$PREVIOUS_HEAD"'",
20+
"new_head": "'"$NEW_HEAD"'",
21+
"branch_name": "'"$BRANCH_NAME"'",
22+
"repository_name": "'"$REPO_NAME"'",
23+
"timestamp": "'"$(date -u +"%Y-%m-%dT%H:%M:%SZ")"'"
24+
}
25+
}' 2>/dev/null || echo "Failed to send repository dispatch event"
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/bin/bash
2+
3+
echo "Git Hook: Post Commit"
4+
5+
# Get commit information
6+
COMMIT_HASH=$(git rev-parse HEAD)
7+
COMMIT_MESSAGE=$(git log -1 --pretty=%B)
8+
COMMIT_AUTHOR=$(git log -1 --pretty="%an <%ae>")
9+
BRANCH_NAME=$(git branch --show-current)
10+
REPO_NAME=$(basename "$(git rev-parse --show-toplevel)")
11+
MODIFIED_FILES=$(git show --pretty=format: --name-only HEAD | jq -R . | jq -s .)
12+
13+
# Get total commit count on branch
14+
DEFAULT_BRANCH=$(git branch --sort=committerdate --format='%(committerdate:short) %(refname:short)' | head -n 1 | cut -d' ' -f2)
15+
if [ "$BRANCH_NAME" != "$DEFAULT_BRANCH" ]; then
16+
BRANCH_COMMIT_COUNT=$(git rev-list --count ${DEFAULT_BRANCH}..${BRANCH_NAME})
17+
BRANCH_COMMIT_MESSAGES=$(git log ${DEFAULT_BRANCH}..${BRANCH_NAME} --pretty=format:'%h%x1f%s' | jq -R -s -c 'split("\n") | map(select(length > 0)) | map(split("\u001f") | {id: .[0], message: .[1]})')
18+
# echo "Total commits on branch '${BRANCH_NAME}' since '${DEFAULT_BRANCH}': ${BRANCH_COMMIT_COUNT}"
19+
else
20+
BRANCH_COMMIT_COUNT=$(git rev-list --count HEAD)
21+
BRANCH_COMMIT_MESSAGES=$(git log --pretty=format:'%h%x1f%s' | jq -R -s -c 'split("\n") | map(select(length > 0)) | map(split("\u001f") | {id: .[0], message: .[1]})')
22+
# echo "Total commits on branch '${DEFAULT_BRANCH}': ${BRANCH_COMMIT_COUNT}"
23+
fi
24+
25+
# Build JSON payload
26+
PAYLOAD=$(jq -n \
27+
--arg event_type "post-commit" \
28+
--arg commit_hash "$COMMIT_HASH" \
29+
--arg commit_message "$COMMIT_MESSAGE" \
30+
--arg commit_author "$COMMIT_AUTHOR" \
31+
--arg branch_name "$BRANCH_NAME" \
32+
--argjson branch_commit_count "$BRANCH_COMMIT_COUNT" \
33+
--argjson branch_commit_messages "$BRANCH_COMMIT_MESSAGES" \
34+
--arg repository_name "$REPO_NAME" \
35+
--argjson modified_files "$MODIFIED_FILES" \
36+
--arg timestamp "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
37+
'{
38+
"event_type": $event_type,
39+
"client_payload": {
40+
"commit_hash": $commit_hash,
41+
"commit_message": $commit_message,
42+
"commit_author": $commit_author,
43+
"branch_name": $branch_name,
44+
"branch_commit_count": $branch_commit_count,
45+
"branch_commit_messages": $branch_commit_messages,
46+
"repository_name": $repository_name,
47+
"modified_files": $modified_files,
48+
"timestamp": $timestamp
49+
}
50+
}')
51+
52+
# Send repository dispatch event
53+
curl -X POST \
54+
-H "Accept: application/vnd.github.v3+json" \
55+
-H "Authorization: token ${GITHUB_TOKEN}" \
56+
"https://api.github.com/repos/${GITHUB_REPOSITORY}/dispatches" \
57+
-d "$PAYLOAD" 2>/dev/null || echo "Failed to send repository dispatch event"
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/bin/bash
2+
3+
echo "Git Hook: Post Merge"
4+
5+
# Get merge information
6+
CURRENT_HEAD=$(git rev-parse HEAD)
7+
BRANCH_NAME=$(git branch --show-current)
8+
LAST_COMMIT_MESSAGE=$(git log -1 --pretty=%B)
9+
MERGE_AUTHOR=$(git log -1 --pretty="%an <%ae>")
10+
REPO_NAME=$(basename "$(git rev-parse --show-toplevel)")
11+
12+
BRANCH_COMMIT_COUNT=$(git rev-list --count HEAD)
13+
BRANCH_COMMIT_MESSAGES=$(git log --pretty=format:'%h%x1f%s' | jq -R -s -c 'split("\n") | map(select(length > 0)) | map(split("\u001f") | {id: .[0], message: .[1]})')
14+
# echo "Total commits on branch '${DEFAULT_BRANCH}': ${BRANCH_COMMIT_COUNT}"
15+
16+
# Build JSON payload
17+
PAYLOAD=$(jq -n \
18+
--arg event_type "post-merge" \
19+
--arg current_head "$CURRENT_HEAD" \
20+
--arg branch_name "$BRANCH_NAME" \
21+
--argjson branch_commit_count "$BRANCH_COMMIT_COUNT" \
22+
--argjson branch_commit_messages "$BRANCH_COMMIT_MESSAGES" \
23+
--arg last_commit_message "$LAST_COMMIT_MESSAGE" \
24+
--arg merge_author "$MERGE_AUTHOR" \
25+
--arg repository_name "$REPO_NAME" \
26+
--arg timestamp "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
27+
'{
28+
"event_type": $event_type,
29+
"client_payload": {
30+
"current_head": $current_head,
31+
"branch_name": $branch_name,
32+
"branch_commit_count": $branch_commit_count,
33+
"branch_commit_messages": $branch_commit_messages,
34+
"last_commit_message": $last_commit_message,
35+
"merge_author": $merge_author,
36+
"repository_name": $repository_name,
37+
"timestamp": $timestamp
38+
}
39+
}')
40+
41+
# Send repository dispatch event
42+
curl -X POST \
43+
-H "Accept: application/vnd.github.v3+json" \
44+
-H "Authorization: token ${GITHUB_TOKEN}" \
45+
"https://api.github.com/repos/${GITHUB_REPOSITORY}/dispatches" \
46+
-d "$PAYLOAD" 2>/dev/null || echo "Failed to send repository dispatch event"
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/bash
2+
3+
# If not running in a Codespace, exit
4+
if [ -z "${CODESPACE_NAME}" ]; then
5+
echo "Not running in a Codespace. Exiting."
6+
exit 0
7+
fi
8+
9+
echo "Exercise Monitor: Event: codespace-created" >> /workspaces/exercise-monitor.log
10+
11+
# Get Codespace information
12+
CODESPACE_NAME="${CODESPACE_NAME}"
13+
14+
# Send repository dispatch event
15+
curl -X POST \
16+
-H "Accept: application/vnd.github.v3+json" \
17+
-H "Authorization: token ${GITHUB_TOKEN}" \
18+
"https://api.github.com/repos/${GITHUB_REPOSITORY}/dispatches" \
19+
-d '{
20+
"event_type": "codespace-created",
21+
"client_payload": {
22+
"codespace_name": "'"$CODESPACE_NAME"'",
23+
"timestamp": "'"$(date -u +"%Y-%m-%dT%H:%M:%SZ")"'"
24+
}
25+
}' 2>/dev/null || echo "Failed to send repository dispatch event"
26+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/bash
2+
3+
# If not running in a Codespace, exit
4+
if [ -z "${CODESPACE_NAME}" ]; then
5+
echo "Not running in a Codespace. Exiting."
6+
exit 0
7+
fi
8+
9+
echo "Exercise Monitor: Event: codespace-started" >> /workspaces/exercise-monitor.log
10+
11+
# Get Codespace information
12+
CODESPACE_NAME="${CODESPACE_NAME}"
13+
14+
# Send repository dispatch event
15+
curl -X POST \
16+
-H "Accept: application/vnd.github.v3+json" \
17+
-H "Authorization: token ${GITHUB_TOKEN}" \
18+
"https://api.github.com/repos/${GITHUB_REPOSITORY}/dispatches" \
19+
-d '{
20+
"event_type": "codespace-started",
21+
"client_payload": {
22+
"codespace_name": "'"$CODESPACE_NAME"'",
23+
"timestamp": "'"$(date -u +"%Y-%m-%dT%H:%M:%SZ")"'"
24+
}
25+
}' 2>/dev/null || echo "Failed to send repository dispatch event"
26+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/bash
2+
3+
# Get config type from argument
4+
CONFIG_TYPE=$1
5+
6+
echo "Exercise Monitor: Event: git-config-changed ($CONFIG_TYPE)" >> /workspaces/exercise-monitor.log
7+
8+
# Send repository dispatch event
9+
curl -X POST \
10+
-H "Accept: application/vnd.github.v3+json" \
11+
-H "Authorization: token ${GITHUB_TOKEN}" \
12+
"https://api.github.com/repos/${GITHUB_REPOSITORY}/dispatches" \
13+
-d '{
14+
"event_type": "git-config-changed",
15+
"client_payload": {
16+
"config_type": "'"$CONFIG_TYPE"'",
17+
"timestamp": "'"$(date -u +"%Y-%m-%dT%H:%M:%SZ")"'"
18+
}
19+
}' 2>/dev/null || echo "Failed to send repository dispatch event"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/bin/bash
2+
3+
# Monitor global config changes
4+
inotifywait -m --include '\.gitconfig$' -e close_write,move,delete /home/vscode | \
5+
while read -r file; do
6+
config_type="global"
7+
/home/vscode/.vscode-remote/data/Machine/exercise-monitor/git-config-changed.sh $config_type
8+
done &
9+
10+
# Monitor .git/config changes in repos of /workspaces directory
11+
inotifywait -m -r --include '\.git/config$' -e close_write,move,delete /workspaces | \
12+
while read -r file; do
13+
config_type="repository"
14+
/home/vscode/.vscode-remote/data/Machine/exercise-monitor/git-config-changed.sh $config_type
15+
done &
16+
17+
echo "Exercise Monitor: Enabled event: git-config-changed" >> /workspaces/exercise-monitor.log
18+
19+
# Heartbeat to keep above monitors alive
20+
while true; do
21+
sleep $((60*5)) # 5 minutes
22+
echo "Exercise Monitor: hearbeat: git-config-monitor" >> /workspaces/exercise-monitor.log
23+
done
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
3+
echo "Exercise Monitor: Installation started"
4+
5+
# Install exercise monitor
6+
cp -r /workspaces/${RepositoryName}/.devcontainer/exercise-monitor /home/vscode/.vscode-remote/data/Machine/exercise-monitor
7+
echo "Exercise Monitor: Copied monitor files to codespace"
8+
9+
# Enable Git hook events
10+
git config --global core.hooksPath /home/vscode/.vscode-remote/data/Machine/exercise-monitor/.githooks
11+
echo "Exercise Monitor: Enabled event: post-commit"
12+
echo "Exercise Monitor: Enabled event: post-checkout"
13+
echo "Exercise Monitor: Enabled event: post-merge"
14+
15+
# Add support for running monitors in the background using tmux and inotify
16+
sudo apk add tmux
17+
sudo apk add inotify-tools
18+
19+
# Trigger codespace created event
20+
/home/vscode/.vscode-remote/data/Machine/exercise-monitor/codespace-created.sh
21+
22+
echo "Exercise Monitor: Installation finished"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
3+
# Trigger event: codespace-started
4+
/home/vscode/.vscode-remote/data/Machine/exercise-monitor/codespace-started.sh
5+
6+
# Watch the Git config
7+
tmux new-session -d -s git_config_monitor '/home/vscode/.vscode-remote/data/Machine/exercise-monitor/git-config-monitor.sh'
8+
9+
# Show running background processes and commands to manually stop.
10+
# tmux ls
11+
# tmux kill-session -t git_config_monitor
12+
# pgrep inotifywait
13+
# for pid in $(pgrep inotifywait); do kill -- "$pid"; done
14+
15+
echo "Exercise Monitor: Started" >> /workspaces/exercise-monitor.log

0 commit comments

Comments
 (0)