525 lines
15 KiB
Bash
525 lines
15 KiB
Bash
#!/usr/bin/env bash
|
||
# ─────────────────────────────────────────────────────────────────────
|
||
# Scenario 3: One-Click Project Initialization
|
||
# Flow: Input description → Create repo → Generate files (README/LICENSE/
|
||
# CONTRIBUTING/CI) → Push to repo → Milestones → Issues →
|
||
# Branch protection → Initial Release
|
||
#
|
||
# Commands chained:
|
||
# 1. repo +create -- create repository
|
||
# 2. git clone -- clone the empty repo locally
|
||
# 3. file generation -- README.md, LICENSE, CONTRIBUTING.md, .gitlink-ci.yml
|
||
# 4. git add/commit/push -- push scaffold files to repo
|
||
# 5. milestone +create -- create project milestones
|
||
# 6. issue +create -- create initial issues
|
||
# 7. branch +protect -- protect default branch
|
||
# 8. release +create -- create initial release
|
||
# ─────────────────────────────────────────────────────────────────────
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
source "$SCRIPT_DIR/lib/common.sh"
|
||
|
||
usage() {
|
||
echo "Usage: $0 --owner OWNER --name REPO_NAME --description DESC [--lang LANG] [--private] [--dry-run]"
|
||
echo ""
|
||
echo " --owner OWNER Repository owner (org or user)"
|
||
echo " --name REPO_NAME Repository name"
|
||
echo " --description DESC Repository description"
|
||
echo " --lang LANG Primary language: go|python|node|java (default: go)"
|
||
echo " --private Make repository private"
|
||
echo " --dry-run Preview actions without executing"
|
||
exit 1
|
||
}
|
||
|
||
PROJ_LANG="go"
|
||
DRY_RUN=false
|
||
OWNER=""
|
||
REPO_NAME=""
|
||
DESCRIPTION=""
|
||
PRIVATE="false"
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
--owner) OWNER="$2"; shift 2 ;;
|
||
--name) REPO_NAME="$2"; shift 2 ;;
|
||
--description) DESCRIPTION="$2"; shift 2 ;;
|
||
--lang) PROJ_LANG="$2"; shift 2 ;;
|
||
--private) PRIVATE="true"; shift ;;
|
||
--dry-run) DRY_RUN="true"; shift ;;
|
||
--help|-h) usage ;;
|
||
*) log_err "Unknown arg: $1"; usage ;;
|
||
esac
|
||
done
|
||
|
||
if [[ -z "$OWNER" || -z "$REPO_NAME" || -z "$DESCRIPTION" ]]; then
|
||
log_err "Missing required parameters: --owner, --name, --description"
|
||
usage
|
||
fi
|
||
|
||
check_auth
|
||
|
||
# ─────────────────────────────────────────────────────────────────────
|
||
log_title "Project Initialization: $OWNER/$REPO_NAME"
|
||
# ─────────────────────────────────────────────────────────────────────
|
||
echo " Owner: $OWNER"
|
||
echo " Name: $REPO_NAME"
|
||
echo " Description: $DESCRIPTION"
|
||
echo " Language: $PROJ_LANG"
|
||
echo " Private: $PRIVATE"
|
||
divider
|
||
|
||
# ── Step 1: Create Repository ────────────────────────────────────────
|
||
log_step "Step 1/8: Creating repository..."
|
||
if [[ "$DRY_RUN" == "true" ]]; then
|
||
log_warn "[DRY RUN] Would create repository: $OWNER/$REPO_NAME"
|
||
else
|
||
REPO_RESULT=$(gl_check repo +create --owner "$OWNER" --name "$REPO_NAME" --description "$DESCRIPTION" --private "$PRIVATE")
|
||
REPO_ID=$(echo "$REPO_RESULT" | jq -r '.data.id // .data.project_id // empty')
|
||
log_ok "Repository created: $OWNER/$REPO_NAME (id: $REPO_ID)"
|
||
fi
|
||
|
||
# ── Step 2: Clone empty repo ─────────────────────────────────────────
|
||
log_step "Step 2/8: Cloning repository..."
|
||
# Build auth URL using token so clone/push don't prompt for password
|
||
if [[ -n "${GITLINK_TOKEN:-}" ]]; then
|
||
CLONE_URL="https://oauth2:${GITLINK_TOKEN}@gitlink.org.cn/$OWNER/$REPO_NAME.git"
|
||
else
|
||
CLONE_URL="https://gitlink.org.cn/$OWNER/$REPO_NAME.git"
|
||
fi
|
||
REPO_URL="https://gitlink.org.cn/$OWNER/$REPO_NAME.git"
|
||
WORK_DIR=$(mktemp -d /tmp/gitlink-init-XXXXXX)
|
||
cleanup() { rm -rf "$WORK_DIR"; }
|
||
trap cleanup EXIT
|
||
|
||
if [[ "$DRY_RUN" == "true" ]]; then
|
||
log_warn "[DRY RUN] Would clone: $REPO_URL → $WORK_DIR"
|
||
else
|
||
git clone "$CLONE_URL" "$WORK_DIR" 2>&1 | tail -1 || true
|
||
log_ok "Cloned to $WORK_DIR"
|
||
fi
|
||
|
||
# ── Step 3: Generate project files ───────────────────────────────────
|
||
log_step "Step 3/8: Generating project scaffold files..."
|
||
|
||
# --- README.md ---
|
||
gen_readme() {
|
||
local lang_section
|
||
case "$PROJ_LANG" in
|
||
go)
|
||
lang_section="### 环境要求
|
||
|
||
- Go 1.21+
|
||
- Git
|
||
|
||
### 安装
|
||
|
||
\`\`\`bash
|
||
git clone https://gitlink.org.cn/$OWNER/$REPO_NAME.git
|
||
cd $REPO_NAME
|
||
go mod download
|
||
go build ./...
|
||
\`\`\`
|
||
|
||
### 使用
|
||
|
||
\`\`\`bash
|
||
go run main.go
|
||
\`\`\`
|
||
|
||
### 测试
|
||
|
||
\`\`\`bash
|
||
go test ./...
|
||
\`\`\`"
|
||
;;
|
||
python)
|
||
lang_section="### 环境要求
|
||
|
||
- Python 3.9+
|
||
- pip
|
||
|
||
### 安装
|
||
|
||
\`\`\`bash
|
||
git clone https://gitlink.org.cn/$OWNER/$REPO_NAME.git
|
||
cd $REPO_NAME
|
||
pip install -r requirements.txt
|
||
\`\`\`
|
||
|
||
### 使用
|
||
|
||
\`\`\`bash
|
||
python main.py
|
||
\`\`\`
|
||
|
||
### 测试
|
||
|
||
\`\`\`bash
|
||
pytest
|
||
\`\`\`"
|
||
;;
|
||
node)
|
||
lang_section="### 环境要求
|
||
|
||
- Node.js 18+
|
||
- npm or yarn
|
||
|
||
### 安装
|
||
|
||
\`\`\`bash
|
||
git clone https://gitlink.org.cn/$OWNER/$REPO_NAME.git
|
||
cd $REPO_NAME
|
||
npm install
|
||
\`\`\`
|
||
|
||
### 使用
|
||
|
||
\`\`\`bash
|
||
npm start
|
||
\`\`\`
|
||
|
||
### 测试
|
||
|
||
\`\`\`bash
|
||
npm test
|
||
\`\`\`"
|
||
;;
|
||
java)
|
||
lang_section="### 环境要求
|
||
|
||
- JDK 17+
|
||
- Maven 3.8+
|
||
|
||
### 安装
|
||
|
||
\`\`\`bash
|
||
git clone https://gitlink.org.cn/$OWNER/$REPO_NAME.git
|
||
cd $REPO_NAME
|
||
mvn clean install
|
||
\`\`\`
|
||
|
||
### 使用
|
||
|
||
\`\`\`bash
|
||
mvn exec:java
|
||
\`\`\`
|
||
|
||
### 测试
|
||
|
||
\`\`\`bash
|
||
mvn test
|
||
\`\`\`"
|
||
;;
|
||
esac
|
||
|
||
cat <<READMEEOF
|
||
# $REPO_NAME
|
||
|
||
$DESCRIPTION
|
||
|
||
## 快速开始
|
||
|
||
$lang_section
|
||
|
||
## 贡献指南
|
||
|
||
详见 [CONTRIBUTING](./CONTRIBUTING.md)。
|
||
|
||
## 许可证
|
||
|
||
本项目基于 MIT 许可证开源 — 详见 [LICENSE](./LICENSE)。
|
||
READMEEOF
|
||
}
|
||
|
||
# --- LICENSE (MIT) ---
|
||
gen_license() {
|
||
local year
|
||
year=$(date +%Y)
|
||
cat <<LICENSEEOF
|
||
MIT License
|
||
|
||
Copyright (c) $year $OWNER
|
||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
of this software and associated documentation files (the "Software"), to deal
|
||
in the Software without restriction, including without limitation the rights
|
||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
copies of the Software, and to permit persons to whom the Software is
|
||
furnished to do so, subject to the following conditions:
|
||
|
||
The above copyright notice and this permission notice shall be included in all
|
||
copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||
SOFTWARE.
|
||
LICENSEEOF
|
||
}
|
||
|
||
# --- CONTRIBUTING.md ---
|
||
gen_contributing() {
|
||
cat <<CONTRIBEOF
|
||
# Contributing to $REPO_NAME
|
||
|
||
Thank you for your interest in contributing!
|
||
|
||
## How to Contribute
|
||
|
||
1. Fork the repository
|
||
2. Create a feature branch: \`git checkout -b feature/my-feature\`
|
||
3. Make your changes
|
||
4. Run tests to ensure everything passes
|
||
5. Commit your changes: \`git commit -m 'feat: add my feature'\`
|
||
6. Push to your fork: \`git push origin feature/my-feature\`
|
||
7. Create a Pull Request
|
||
|
||
## Code Style
|
||
|
||
- Follow the existing code style
|
||
- Write meaningful commit messages following [Conventional Commits](https://www.conventionalcommits.org/)
|
||
- Add tests for new features
|
||
- Update documentation as needed
|
||
|
||
## Reporting Issues
|
||
|
||
- Use the [issue tracker](https://gitlink.org.cn/$OWNER/$REPO_NAME/issues)
|
||
- Include steps to reproduce
|
||
- Include environment details (OS, language version, etc.)
|
||
|
||
## Code of Conduct
|
||
|
||
Please be respectful and constructive in all interactions.
|
||
CONTRIBEOF
|
||
}
|
||
|
||
# --- .gitlink-ci.yml ---
|
||
gen_ci_config() {
|
||
case "$PROJ_LANG" in
|
||
go)
|
||
cat <<CIEOF
|
||
image: golang:1.21
|
||
|
||
stages:
|
||
- test
|
||
- build
|
||
|
||
test:
|
||
stage: test
|
||
script:
|
||
- go mod download
|
||
- go test ./... -v -cover
|
||
|
||
build:
|
||
stage: build
|
||
script:
|
||
- go build ./...
|
||
CIEOF
|
||
;;
|
||
python)
|
||
cat <<CIEOF
|
||
image: python:3.9
|
||
|
||
stages:
|
||
- test
|
||
- lint
|
||
|
||
test:
|
||
stage: test
|
||
script:
|
||
- pip install -r requirements.txt
|
||
- pytest -v --cov
|
||
|
||
lint:
|
||
stage: lint
|
||
script:
|
||
- pip install flake8
|
||
- flake8 .
|
||
CIEOF
|
||
;;
|
||
node)
|
||
cat <<CIEOF
|
||
image: node:18
|
||
|
||
stages:
|
||
- test
|
||
- build
|
||
|
||
test:
|
||
stage: test
|
||
script:
|
||
- npm ci
|
||
- npm test -- --coverage
|
||
|
||
build:
|
||
stage: build
|
||
script:
|
||
- npm ci
|
||
- npm run build
|
||
CIEOF
|
||
;;
|
||
java)
|
||
cat <<CIEOF
|
||
image: maven:3.8-openjdk-17
|
||
|
||
stages:
|
||
- test
|
||
- build
|
||
|
||
test:
|
||
stage: test
|
||
script:
|
||
- mvn test
|
||
|
||
build:
|
||
stage: build
|
||
script:
|
||
- mvn package -DskipTests
|
||
CIEOF
|
||
;;
|
||
esac
|
||
}
|
||
|
||
if [[ "$DRY_RUN" == "true" ]]; then
|
||
log_warn "[DRY RUN] Would generate: README.md, LICENSE, CONTRIBUTING.md, .gitlink-ci.yml"
|
||
else
|
||
gen_readme > "$WORK_DIR/README.md"
|
||
gen_license > "$WORK_DIR/LICENSE"
|
||
gen_contributing > "$WORK_DIR/CONTRIBUTING.md"
|
||
gen_ci_config > "$WORK_DIR/.gitlink-ci.yml"
|
||
log_ok "Generated: README.md, LICENSE, CONTRIBUTING.md, .gitlink-ci.yml"
|
||
fi
|
||
|
||
# ── Step 4: Push files to repo ───────────────────────────────────────
|
||
log_step "Step 4/8: Pushing scaffold files to repository..."
|
||
if [[ "$DRY_RUN" == "true" ]]; then
|
||
log_warn "[DRY RUN] Would git add/commit/push to $REPO_URL"
|
||
else
|
||
pushd "$WORK_DIR" > /dev/null
|
||
git add README.md LICENSE CONTRIBUTING.md .gitlink-ci.yml
|
||
git -c user.name="$OWNER" -c user.email="$OWNER@gitlink.org.cn" \
|
||
commit -m "chore: initialize project scaffold
|
||
|
||
- Add README.md with getting-started guide
|
||
- Add MIT LICENSE
|
||
- Add CONTRIBUTING.md with guidelines
|
||
- Add .gitlink-ci.yml CI pipeline configuration" 2>&1 | tail -1
|
||
git push -u origin master 2>&1 | tail -1
|
||
popd > /dev/null
|
||
log_ok "Scaffold files pushed to master"
|
||
fi
|
||
|
||
# ── Step 5: Create Milestone ─────────────────────────────────────────
|
||
log_step "Step 5/8: Creating initial milestone..."
|
||
|
||
MILESTONES=(
|
||
"v1.0.0 - First Release|First official release milestone"
|
||
)
|
||
|
||
if [[ "$DRY_RUN" == "true" ]]; then
|
||
log_warn "[DRY RUN] Would create ${#MILESTONES[@]} milestone"
|
||
else
|
||
for entry in "${MILESTONES[@]}"; do
|
||
IFS='|' read -r ms_title ms_desc <<< "$entry"
|
||
MS_RESULT=$(gl_run milestone +create --owner "$OWNER" --repo "$REPO_NAME" \
|
||
--name "$ms_title" --description "$ms_desc" 2>&1) || true
|
||
if [[ "$(json_ok "$MS_RESULT")" == "true" ]]; then
|
||
log_ok "Milestone created: $ms_title"
|
||
else
|
||
log_warn "Milestone creation may have failed: $ms_title"
|
||
fi
|
||
done
|
||
fi
|
||
|
||
# ── Step 6: Create Welcome Issue ─────────────────────────────────────
|
||
log_step "Step 6/8: Creating welcome issue..."
|
||
|
||
ISSUES_TO_CREATE=(
|
||
"Welcome to $REPO_NAME|欢迎来到 **${REPO_NAME}** 的仓库,这是本仓库的第一条issue!!|welcome"
|
||
)
|
||
|
||
if [[ "$DRY_RUN" == "true" ]]; then
|
||
log_warn "[DRY RUN] Would create ${#ISSUES_TO_CREATE[@]} initial issues"
|
||
else
|
||
for entry in "${ISSUES_TO_CREATE[@]}"; do
|
||
IFS='|' read -r title body label <<< "$entry"
|
||
ISSUE_RESULT=$(gl_run issue +create --owner "$OWNER" --repo "$REPO_NAME" \
|
||
--title "$title" --body "$body" 2>&1) || true
|
||
ISSUE_NUM=$(echo "$ISSUE_RESULT" | jq -r '.data.id // .data.number // empty')
|
||
if [[ -n "$ISSUE_NUM" ]]; then
|
||
gl_run issue +label-add --owner "$OWNER" --repo "$REPO_NAME" --number "$ISSUE_NUM" --labels "$label" > /dev/null 2>&1 || true
|
||
log_ok "Issue created: #$ISSUE_NUM - $title"
|
||
else
|
||
log_warn "Issue creation may have failed: $title"
|
||
fi
|
||
done
|
||
fi
|
||
|
||
# ── Step 7: Protect Default Branch ───────────────────────────────────
|
||
log_step "Step 7/8: Protecting master branch..."
|
||
if [[ "$DRY_RUN" == "true" ]]; then
|
||
log_warn "[DRY RUN] Would protect branch 'master'"
|
||
else
|
||
PROTECT_RESULT=$(gl_run branch +protect --owner "$OWNER" --repo "$REPO_NAME" --name master 2>&1) || true
|
||
if [[ "$(json_ok "$PROTECT_RESULT")" == "true" ]]; then
|
||
log_ok "Branch 'master' protected"
|
||
else
|
||
log_warn "Branch protection may have failed (may require admin permissions)"
|
||
fi
|
||
fi
|
||
|
||
# ── Step 8: Create Initial Release ───────────────────────────────────
|
||
log_step "Step 8/8: Creating initial release v0.1.0..."
|
||
|
||
RELEASE_BODY="# v0.1.0 - Initial Release
|
||
|
||
## What's New
|
||
- Project initialized with $PROJ_LANG template
|
||
- README, LICENSE, CONTRIBUTING guide in repository
|
||
- CI/CD pipeline configuration (.gitlink-ci.yml)
|
||
- ${#MILESTONES[@]} project milestone created
|
||
- ${#ISSUES_TO_CREATE[@]} initial issues filed
|
||
- Branch protection enabled
|
||
|
||
## Next Steps
|
||
- [ ] Setup CI/CD pipeline
|
||
- [ ] Write comprehensive tests
|
||
- [ ] Complete documentation
|
||
- [ ] First feature implementation
|
||
|
||
---
|
||
*Auto-initialized by gitlink-cli project-init workflow*"
|
||
|
||
if [[ "$DRY_RUN" == "true" ]]; then
|
||
log_warn "[DRY RUN] Would create release v0.1.0"
|
||
else
|
||
RELEASE_RESULT=$(gl_run release +create --owner "$OWNER" --repo "$REPO_NAME" \
|
||
--tag "v0.1.0" --name "Initial Release" --body "$RELEASE_BODY" 2>&1) || true
|
||
if [[ "$(json_ok "$RELEASE_RESULT")" == "true" ]]; then
|
||
log_ok "Release v0.1.0 created"
|
||
else
|
||
log_warn "Release creation may have failed"
|
||
fi
|
||
fi
|
||
|
||
# ─────────────────────────────────────────────────────────────────────
|
||
log_title "Project Initialization Complete"
|
||
# ─────────────────────────────────────────────────────────────────────
|
||
|
||
echo -e "${GREEN}Created:${NC}"
|
||
echo " Repository: $OWNER/$REPO_NAME"
|
||
echo " Files: README.md, LICENSE, CONTRIBUTING.md, .gitlink-ci.yml"
|
||
echo " Milestones: ${#MILESTONES[@]} milestone"
|
||
echo " Issues: ${#ISSUES_TO_CREATE[@]} initial issues"
|
||
echo " Branch: master (protected)"
|
||
echo " Release: v0.1.0"
|
||
echo ""
|
||
echo -e "${CYAN}Next steps:${NC}"
|
||
echo " 1. Clone: git clone $REPO_URL"
|
||
echo " 2. Start coding and close the first issue"
|
||
echo " 3. CI/CD will trigger on your first push"
|
||
echo ""
|