Initialiseert lokale scripts voor een nieuw GitLab Rust-project.
Gebruik: voer uit vanuit de root van je nieuwe project:
mkdir ~/git/mijn-project && cd ~/git/mijn-project
git init
~/boilerplate-git/new-project.sh
Het script vraagt naar GitLab project path, binary naam, poort en token, en maakt aan:
push.sh, bump.sh, release.sh, ctl.sh, .env, .gitignore — geen van deze wordt gecommit.
#!/usr/bin/env bash
# new-project.sh — initialize local project scripts for a GitLab Rust project
#
# Run this from the root of your new project:
# ~/boilerplate-git/new-project.sh
#
# Creates: push.sh, bump.sh, release.sh, ctl.sh, .env, .gitignore (if absent)
# None of these files are committed to git.
set -euo pipefail
TARGET_DIR="$(pwd)"
echo "=== New project setup ==="
echo "Target: ${TARGET_DIR}"
echo ""
# ── Vragen ────────────────────────────────────────────────────────────────────
read -rp "GitLab project path (bijv. dexter1-dev/myproject): " GITLAB_PATH
if [[ -z "${GITLAB_PATH}" ]]; then
echo "Fout: GitLab project path mag niet leeg zijn." >&2
exit 1
fi
# URL-encode slash for API calls (dexter1-dev/myproject → dexter1-dev%2Fmyproject)
GITLAB_PROJECT_ENCODED="${GITLAB_PATH/\//%2F}"
GITLAB_USER="${GITLAB_PATH%%/*}"
GITLAB_REPO="${GITLAB_PATH##*/}"
GITLAB_URL="https://gitlab.com/${GITLAB_PATH}.git"
read -rp "Naam van de hoofd-binary (standaard: ${GITLAB_REPO}): " BINARY_NAME
BINARY_NAME="${BINARY_NAME:-${GITLAB_REPO}}"
read -rp "Naam van de admin-binary (leeg = geen): " ADMIN_NAME
read -rp "Standaard poort (standaard: 3000): " PORT
PORT="${PORT:-3000}"
read -rsp "GitLab token (glpat-...): " GITLAB_TOKEN
echo ""
if [[ -z "${GITLAB_TOKEN}" ]]; then
echo "Fout: token mag niet leeg zijn." >&2
exit 1
fi
echo ""
# ── .env ─────────────────────────────────────────────────────────────────────
if [[ -f .env ]]; then
echo "==> .env bestaat al, wordt overgeslagen."
else
cat > .env <<EOF
GITLAB_TOKEN=${GITLAB_TOKEN}
EOF
chmod 600 .env
echo "==> .env aangemaakt."
fi
# ── .gitignore ────────────────────────────────────────────────────────────────
if [[ ! -f .gitignore ]]; then
cat > .gitignore <<'EOF'
# Rust build artifacts
/target/
# Local scripts
push.sh
bump.sh
release.sh
ctl.sh
# Local environment (contains tokens)
.env
# Claude Code session data
.claude/
# OS
.DS_Store
*.log
EOF
echo "==> .gitignore aangemaakt."
else
for entry in push.sh bump.sh release.sh ctl.sh .env ".claude/"; do
grep -qxF "${entry}" .gitignore || echo "${entry}" >> .gitignore
done
echo "==> .gitignore bijgewerkt."
fi
# ── push.sh ───────────────────────────────────────────────────────────────────
cat > push.sh <<EOF
#!/bin/bash
# Push project naar GitLab: https://gitlab.com/${GITLAB_PATH}
set -euo pipefail
BRANCH="main"
REMOTE="origin"
cd "\$(dirname "\$0")"
[[ -f .env ]] && source .env
REMOTE_URL="\$(git remote get-url origin 2>/dev/null || true)"
if [[ -n "\${GITLAB_TOKEN:-}" ]]; then
REMOTE_URL="https://${GITLAB_USER}:\${GITLAB_TOKEN}@gitlab.com/${GITLAB_PATH}.git"
fi
echo "=== ${GITLAB_REPO} push naar GitLab ==="
if ! git remote get-url "\$REMOTE" &>/dev/null; then
echo "Remote '\$REMOTE' niet gevonden. Voeg toe met:"
echo " git remote add origin ${GITLAB_URL}"
exit 1
fi
git add -A
echo ""
echo "--- Wijzigingen ---"
git status --short
echo ""
if git diff --cached --quiet; then
echo "Geen wijzigingen om te committen."
else
MSG="\${1:-"update \$(date '+%Y-%m-%d %H:%M')"}"
git commit -m "\$MSG"
fi
echo "Pushen naar \$REMOTE/\$BRANCH ..."
git push -u "\${REMOTE_URL:-\$REMOTE}" "\$BRANCH"
echo ""
echo "Klaar! Zie: https://gitlab.com/${GITLAB_PATH}"
EOF
chmod +x push.sh
echo "==> push.sh aangemaakt."
# ── bump.sh ───────────────────────────────────────────────────────────────────
cat > bump.sh <<'BUMP'
#!/usr/bin/env bash
# bump.sh — increase version and commit
#
# Usage:
# ./bump.sh # patch (0.1.0 → 0.1.1)
# ./bump.sh minor # minor (0.1.1 → 0.2.0)
# ./bump.sh major # major (0.2.0 → 1.0.0)
# ./bump.sh 1.2.3 # exact version
set -euo pipefail
cd "$(dirname "$0")"
BUMP="${1:-patch}"
CURRENT=$(grep '^version' Cargo.toml | head -1 | sed 's/.*= *"\(.*\)"/\1/')
IFS='.' read -r MAJOR MINOR PATCH <<< "${CURRENT}"
case "${BUMP}" in
major) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;;
minor) MINOR=$((MINOR + 1)); PATCH=0 ;;
patch) PATCH=$((PATCH + 1)) ;;
[0-9]*.[0-9]*.[0-9]*) MAJOR=""; MINOR=""; PATCH=""; VERSION="${BUMP}" ;;
*)
echo "Usage: $0 [patch|minor|major|x.y.z]" >&2
exit 1
;;
esac
VERSION="${VERSION:-${MAJOR}.${MINOR}.${PATCH}}"
if [[ "${VERSION}" == "${CURRENT}" ]]; then
echo "Version is already ${CURRENT}, nothing to do." >&2
exit 1
fi
echo "==> ${CURRENT} -> ${VERSION}"
sed -i "0,/^version = \"${CURRENT}\"/s//version = \"${VERSION}\"/" Cargo.toml
if [[ -f CHANGELOG.md ]] && grep -q '^\#\# \[Unreleased\]' CHANGELOG.md; then
TODAY=$(date '+%Y-%m-%d')
sed -i "0,/^## \[Unreleased\].*/s//## [${VERSION}] - ${TODAY}/" CHANGELOG.md
sed -i "/^## \[Unreleased\].*/d" CHANGELOG.md
echo "==> CHANGELOG.md updated: [Unreleased] → [${VERSION}] - ${TODAY}"
fi
cargo build --release
git add Cargo.toml Cargo.lock CHANGELOG.md
git commit -m "Bump version to ${VERSION}"
echo "==> Done. Use ./push.sh and then ./release.sh to tag and publish."
BUMP
chmod +x bump.sh
echo "==> bump.sh aangemaakt."
# ── release.sh ────────────────────────────────────────────────────────────────
ADMIN_BLOCK=""
ADMIN_UPLOAD_BLOCK=""
ADMIN_LINK_BLOCK=""
if [[ -n "${ADMIN_NAME}" ]]; then
ADMIN_BLOCK='
ADMIN_BINARY_NAME="'"${ADMIN_NAME}"'-linux-x86_64"
ADMIN_BINARY_PATH="target/release/'"${ADMIN_NAME}"'"'
ADMIN_UPLOAD_BLOCK='
echo "==> Admin binary uploaden (\${ADMIN_BINARY_NAME})..."
HTTP=$(curl -s -o /dev/null -w "%{http_code}" \
--header "PRIVATE-TOKEN: \${GITLAB_TOKEN}" \
--upload-file "\${ADMIN_BINARY_PATH}" \
"https://gitlab.com/api/v4/projects/\${PROJECT}/packages/generic/'"${BINARY_NAME}"'/\${VERSION}/\${ADMIN_BINARY_NAME}")
[[ "\${HTTP}" == "201" || "\${HTTP}" == "200" ]] || { echo "Fout admin upload (HTTP \${HTTP})." >&2; exit 1; }
echo " Admin binary geupload (HTTP \${HTTP})."'
ADMIN_LINK_BLOCK=' ,
{
\"name\": \"\${ADMIN_BINARY_NAME}\",
\"url\": \"https://gitlab.com/api/v4/projects/\${PROJECT}/packages/generic/'"${BINARY_NAME}"'/\${VERSION}/\${ADMIN_BINARY_NAME}\",
\"link_type\": \"package\"
}'
fi
cat > release.sh <<EOF
#!/usr/bin/env bash
set -euo pipefail
GITLAB_TOKEN="\${GITLAB_TOKEN:?Set GITLAB_TOKEN as environment variable or add to .env}"
PROJECT="${GITLAB_PROJECT_ENCODED}"
BINARY_NAME="${BINARY_NAME}-linux-x86_64"
BINARY_PATH="target/release/${BINARY_NAME}"${ADMIN_BLOCK}
cd "\$(dirname "\$0")"
[[ -f .env ]] && source .env
REPLACE=""
[[ "\${1:-}" == "--replace" ]] && REPLACE=1
GIT_REMOTE="https://${GITLAB_USER}:\${GITLAB_TOKEN}@gitlab.com/${GITLAB_PATH}.git"
VERSION=\$(grep '^version' Cargo.toml | head -1 | sed 's/.*= *\"\(.*\)\"/\1/')
TAG="v\${VERSION}"
echo "==> Releasing \${TAG}\${REPLACE:+ (replace)}"
if [[ "\${REPLACE}" == "1" ]]; then
echo "==> Removing existing release..."
HTTP=\$(curl -s -o /dev/null -w "%{http_code}" \\
--header "PRIVATE-TOKEN: \${GITLAB_TOKEN}" \\
--request DELETE \\
"https://gitlab.com/api/v4/projects/\${PROJECT}/releases/\${TAG}")
[[ "\${HTTP}" == "200" ]] && echo " Release removed." || echo " Release not found (HTTP \${HTTP}), continuing."
echo "==> Removing and recreating tag..."
git tag -d "\${TAG}" 2>/dev/null || true
HTTP=\$(curl -s -o /dev/null -w "%{http_code}" \\
--header "PRIVATE-TOKEN: \${GITLAB_TOKEN}" \\
--request DELETE \\
"https://gitlab.com/api/v4/projects/\${PROJECT}/repository/tags/\${TAG}")
[[ "\${HTTP}" == "200" ]] && echo " Remote tag removed." || echo " Remote tag not found (HTTP \${HTTP})."
fi
echo "==> Building (release)..."
cargo build --release
if ! git tag -l | grep -q "^\${TAG}\$"; then
git tag "\${TAG}"
fi
echo "==> Pushing tag..."
git push "\${GIT_REMOTE}" "\${TAG}" \${REPLACE:+--force}
echo "==> Uploading binary (\${BINARY_NAME})..."
HTTP=\$(curl -s -o /dev/null -w "%{http_code}" \\
--header "PRIVATE-TOKEN: \${GITLAB_TOKEN}" \\
--upload-file "\${BINARY_PATH}" \\
"https://gitlab.com/api/v4/projects/\${PROJECT}/packages/generic/${BINARY_NAME}/\${VERSION}/\${BINARY_NAME}")
[[ "\${HTTP}" == "201" || "\${HTTP}" == "200" ]] || { echo "Binary upload error (HTTP \${HTTP})." >&2; exit 1; }
echo " Binary uploaded."
${ADMIN_UPLOAD_BLOCK}
if [[ -f CHANGELOG.md ]]; then
DESCRIPTION=\$(awk "/^\#\# \[?\${VERSION}\]?/{found=1; next} found && /^\#\# /{exit} found{print}" CHANGELOG.md)
else
DESCRIPTION="Release \${TAG}."
fi
echo "==> Creating GitLab release..."
RESULT=\$(curl -s -w "\n%{http_code}" \\
--header "PRIVATE-TOKEN: \${GITLAB_TOKEN}" \\
--header "Content-Type: application/json" \\
--request POST \\
--data "{
\"name\": \"${BINARY_NAME} \${TAG}\",
\"tag_name\": \"\${TAG}\",
\"description\": \$(echo "\${DESCRIPTION}" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))'),
\"assets\": {
\"links\": [
{
\"name\": \"\${BINARY_NAME}\",
\"url\": \"https://gitlab.com/api/v4/projects/\${PROJECT}/packages/generic/${BINARY_NAME}/\${VERSION}/\${BINARY_NAME}\",
\"link_type\": \"package\"
}${ADMIN_LINK_BLOCK}
]
}
}" \\
"https://gitlab.com/api/v4/projects/\${PROJECT}/releases")
HTTP=\$(echo "\${RESULT}" | tail -1)
BODY=\$(echo "\${RESULT}" | head -n -1)
if [[ "\${HTTP}" == "201" ]]; then
echo "==> Release created: https://gitlab.com/${GITLAB_PATH}/-/releases/\${TAG}"
else
echo "Error creating release (HTTP \${HTTP}):" >&2
echo "\${BODY}" >&2
exit 1
fi
EOF
chmod +x release.sh
echo "==> release.sh aangemaakt."
# ── ctl.sh ────────────────────────────────────────────────────────────────────
cat > ctl.sh <<EOF
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="\$(cd "\$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
BINARY="\$SCRIPT_DIR/target/release/${BINARY_NAME}"
MDS_DIR="\${MDS_DIR:-\$SCRIPT_DIR/demo}"
MDS_PORT="\${MDS_PORT:-${PORT}}"
MDS_LOGFILE="\${MDS_LOGFILE:-\$SCRIPT_DIR/${BINARY_NAME}.log}"
MDS_ACCESS_LOG="\${MDS_ACCESS_LOG:-\$SCRIPT_DIR/access.log}"
MDS_CONFIG="\${MDS_CONFIG:-}"
cmd_stop() {
if pgrep -f "${BINARY_NAME}.*--port \${MDS_PORT}" > /dev/null; then
pkill -f "${BINARY_NAME}.*--port \${MDS_PORT}"
echo "${BINARY_NAME} stopped."
else
echo "${BINARY_NAME} was not running."
fi
}
cmd_build() {
echo "Building..."
cd "\$SCRIPT_DIR"
cargo build --release
[[ "\${1:-}" == "--start" ]] && cmd_start
}
cmd_start() {
if [[ ! -x "\$BINARY" ]]; then
echo "Error: \$BINARY not found. Use './ctl.sh build --start'." >&2
exit 1
fi
if pgrep -f "${BINARY_NAME}.*--port \${MDS_PORT}" > /dev/null; then
pkill -f "${BINARY_NAME}.*--port \${MDS_PORT}"
sleep 1
fi
nohup "\$BINARY" \\
--dir "\$MDS_DIR" \\
--port "\$MDS_PORT" \\
--access-log "\$MDS_ACCESS_LOG" \\
\${MDS_CONFIG:+--config "\$MDS_CONFIG"} \\
>> "\$MDS_LOGFILE" 2>&1 &
sleep 1
if pgrep -f "${BINARY_NAME}.*--port \${MDS_PORT}" > /dev/null; then
echo "${BINARY_NAME} started : http://0.0.0.0:\${MDS_PORT}"
else
echo "Error: server did not start. Check \$MDS_LOGFILE" >&2
exit 1
fi
}
cmd_restart() { cmd_stop; sleep 1; cmd_start; }
cmd_status() {
PID=\$(pgrep -f "${BINARY_NAME}.*--port \${MDS_PORT}" || true)
if [[ -n "\${PID}" ]]; then
echo "${BINARY_NAME} running (pid=\${PID}) on http://0.0.0.0:\${MDS_PORT}"
else
echo "${BINARY_NAME} is not running."
fi
}
case "\${1:-}" in
start) cmd_start ;;
stop) cmd_stop ;;
restart) cmd_restart ;;
status) cmd_status ;;
build) cmd_build "\${2:-}" ;;
*)
echo "Usage: \$0 {start|stop|restart|status|build} [--start]"
exit 1 ;;
esac
EOF
chmod +x ctl.sh
echo "==> ctl.sh aangemaakt."
# ── git remote ────────────────────────────────────────────────────────────────
if git rev-parse --git-dir > /dev/null 2>&1; then
if ! git remote get-url origin &>/dev/null; then
git remote add origin "${GITLAB_URL}"
echo "==> Git remote 'origin' ingesteld op ${GITLAB_URL}"
else
echo "==> Git remote bestaat al: $(git remote get-url origin)"
fi
else
echo "==> Geen git repo gevonden. Initialiseer met: git init"
fi
echo ""
echo "Klaar! Bestanden aangemaakt in ${TARGET_DIR}:"
echo " push.sh, bump.sh, release.sh, ctl.sh, .env, .gitignore"
echo ""
echo "Volgende stappen:"
echo " 1. git init (als nog niet gedaan)"
echo " 2. ./ctl.sh build --start"
echo " 3. ./push.sh 'first commit'"