forked from Gitlink/gitlink-cli
543 lines
14 KiB
PowerShell
543 lines
14 KiB
PowerShell
# ----------------------------------------------------------------
|
||
# 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
|
||
# ----------------------------------------------------------------
|
||
#Requires -Version 5.1
|
||
|
||
param(
|
||
[string]$Owner = "",
|
||
[string]$Name = "",
|
||
[string]$Description = "",
|
||
[string]$Lang = "go",
|
||
[switch]$Private,
|
||
[switch]$DryRun,
|
||
[switch]$Help
|
||
)
|
||
|
||
$ErrorActionPreference = "Stop"
|
||
Import-Module "$PSScriptRoot/lib/common.psm1" -Force -WarningAction SilentlyContinue
|
||
|
||
if ($Help) {
|
||
Write-Host "Usage: powershell 03-project-init.ps1 -Owner OWNER -Name REPO_NAME -Description DESC [-Lang go|python|node|java] [-Private] [-DryRun]"
|
||
exit 0
|
||
}
|
||
|
||
if (-not $Name) { Log-Err "Name is required (use -Help for usage)"; exit 1 }
|
||
if (-not $Description) { Log-Err "Description is required (use -Help for usage)"; exit 1 }
|
||
|
||
Check-Auth
|
||
if (-not $Owner) {
|
||
$detected = Detect-OwnerRepo
|
||
$Owner = $detected.Owner
|
||
}
|
||
|
||
# ----------------------------------------------------------------
|
||
Log-Title "Project Initialization: $Owner/$Name"
|
||
# ----------------------------------------------------------------
|
||
Write-Host " Owner: $Owner"
|
||
Write-Host " Name: $Name"
|
||
Write-Host " Description: $Description"
|
||
Write-Host " Language: $Lang"
|
||
Write-Host " Private: $($Private.IsPresent)"
|
||
Divider
|
||
|
||
# -- Step 1: Create Repository --
|
||
Log-Step "Step 1/8: Creating repository..."
|
||
if ($DryRun) {
|
||
Log-Warn "[DRY RUN] Would create repository: $Owner/$Name"
|
||
} else {
|
||
$privateStr = if ($Private) { "true" } else { "false" }
|
||
$repoResult = Invoke-GLCheck "repo", "+create", "--owner", $Owner, "--name", $Name, "--description", $Description, "--private", $privateStr
|
||
if ($repoResult) {
|
||
Log-Ok "Repository created: $Owner/$Name"
|
||
} else {
|
||
Log-Err "Repository creation failed"
|
||
exit 1
|
||
}
|
||
}
|
||
|
||
# -- Step 2: Clone empty repo --
|
||
Log-Step "Step 2/8: Cloning repository..."
|
||
$repoUrl = "https://gitlink.org.cn/$Owner/$Name.git"
|
||
if ($env:GITLINK_TOKEN) {
|
||
$cloneUrl = "https://oauth2:$($env:GITLINK_TOKEN)@gitlink.org.cn/$Owner/$Name.git"
|
||
} else {
|
||
$cloneUrl = $repoUrl
|
||
}
|
||
$workDir = Join-Path $env:TEMP "gitlink-init-$([System.Guid]::NewGuid().ToString('N').Substring(0, 8))"
|
||
|
||
if ($DryRun) {
|
||
Log-Warn "[DRY RUN] Would clone: $repoUrl -> $workDir"
|
||
} else {
|
||
git clone $cloneUrl $workDir 2>&1 | Select-Object -Last 1
|
||
Log-Ok "Cloned to $workDir"
|
||
}
|
||
|
||
# -- Step 3: Generate project files --
|
||
Log-Step "Step 3/8: Generating project scaffold files..."
|
||
|
||
function Get-ReadmeContent {
|
||
$langSection = switch ($Lang) {
|
||
"go" {
|
||
@"
|
||
### 环境要求
|
||
|
||
- Go 1.21+
|
||
- Git
|
||
|
||
### 安装
|
||
|
||
```bash
|
||
git clone https://gitlink.org.cn/$Owner/$Name.git
|
||
cd $Name
|
||
go mod download
|
||
go build ./...
|
||
```
|
||
|
||
### 使用
|
||
|
||
```bash
|
||
go run main.go
|
||
```
|
||
|
||
### 测试
|
||
|
||
```bash
|
||
go test ./...
|
||
```
|
||
"@
|
||
}
|
||
"python" {
|
||
@"
|
||
### 环境要求
|
||
|
||
- Python 3.9+
|
||
- pip
|
||
|
||
### 安装
|
||
|
||
```bash
|
||
git clone https://gitlink.org.cn/$Owner/$Name.git
|
||
cd $Name
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
### 使用
|
||
|
||
```bash
|
||
python main.py
|
||
```
|
||
|
||
### 测试
|
||
|
||
```bash
|
||
pytest
|
||
```
|
||
"@
|
||
}
|
||
"node" {
|
||
@"
|
||
### 环境要求
|
||
|
||
- Node.js 18+
|
||
- npm or yarn
|
||
|
||
### 安装
|
||
|
||
```bash
|
||
git clone https://gitlink.org.cn/$Owner/$Name.git
|
||
cd $Name
|
||
npm install
|
||
```
|
||
|
||
### 使用
|
||
|
||
```bash
|
||
npm start
|
||
```
|
||
|
||
### 测试
|
||
|
||
```bash
|
||
npm test
|
||
```
|
||
"@
|
||
}
|
||
"java" {
|
||
@"
|
||
### 环境要求
|
||
|
||
- JDK 17+
|
||
- Maven 3.8+
|
||
|
||
### 安装
|
||
|
||
```bash
|
||
git clone https://gitlink.org.cn/$Owner/$Name.git
|
||
cd $Name
|
||
mvn clean install
|
||
```
|
||
|
||
### 使用
|
||
|
||
```bash
|
||
mvn exec:java
|
||
```
|
||
|
||
### 测试
|
||
|
||
```bash
|
||
mvn test
|
||
```
|
||
"@
|
||
}
|
||
default { "" }
|
||
}
|
||
|
||
return @"
|
||
# $Name
|
||
|
||
$Description
|
||
|
||
## 快速开始
|
||
|
||
$langSection
|
||
|
||
## 贡献指南
|
||
|
||
详见 [CONTRIBUTING](./CONTRIBUTING.md)。
|
||
|
||
## 许可证
|
||
|
||
本项目基于 MIT 许可证开源 — 详见 [LICENSE](./LICENSE)。
|
||
"@
|
||
}
|
||
|
||
function Get-LicenseContent {
|
||
$year = (Get-Date).Year
|
||
return @"
|
||
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.
|
||
"@
|
||
}
|
||
|
||
function Get-ContributingContent {
|
||
return @"
|
||
# Contributing to $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/$Name/issues)
|
||
- Include steps to reproduce
|
||
- Include environment details (OS, language version, etc.)
|
||
|
||
## Code of Conduct
|
||
|
||
Please be respectful and constructive in all interactions.
|
||
"@
|
||
}
|
||
|
||
function Get-CIConfigContent {
|
||
switch ($Lang) {
|
||
"go" {
|
||
return @"
|
||
image: golang:1.21
|
||
|
||
stages:
|
||
- test
|
||
- build
|
||
|
||
test:
|
||
stage: test
|
||
script:
|
||
- go mod download
|
||
- go test ./... -v -cover
|
||
|
||
build:
|
||
stage: build
|
||
script:
|
||
- go build ./...
|
||
"@
|
||
}
|
||
"python" {
|
||
return @"
|
||
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 .
|
||
"@
|
||
}
|
||
"node" {
|
||
return @"
|
||
image: node:18
|
||
|
||
stages:
|
||
- test
|
||
- build
|
||
|
||
test:
|
||
stage: test
|
||
script:
|
||
- npm ci
|
||
- npm test -- --coverage
|
||
|
||
build:
|
||
stage: build
|
||
script:
|
||
- npm ci
|
||
- npm run build
|
||
"@
|
||
}
|
||
"java" {
|
||
return @"
|
||
image: maven:3.8-openjdk-17
|
||
|
||
stages:
|
||
- test
|
||
- build
|
||
|
||
test:
|
||
stage: test
|
||
script:
|
||
- mvn test
|
||
|
||
build:
|
||
stage: build
|
||
script:
|
||
- mvn package -DskipTests
|
||
"@
|
||
}
|
||
default {
|
||
return "# TODO: configure CI/CD pipeline for $Lang"
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($DryRun) {
|
||
Log-Warn "[DRY RUN] Would generate: README.md, LICENSE, CONTRIBUTING.md, .gitlink-ci.yml"
|
||
} else {
|
||
$utf8 = [System.Text.UTF8Encoding]::new($false)
|
||
[System.IO.File]::WriteAllText("$workDir\README.md", (Get-ReadmeContent), $utf8)
|
||
[System.IO.File]::WriteAllText("$workDir\LICENSE", (Get-LicenseContent), $utf8)
|
||
[System.IO.File]::WriteAllText("$workDir\CONTRIBUTING.md", (Get-ContributingContent), $utf8)
|
||
[System.IO.File]::WriteAllText("$workDir\.gitlink-ci.yml", (Get-CIConfigContent), $utf8)
|
||
Log-Ok "Generated: README.md, LICENSE, CONTRIBUTING.md, .gitlink-ci.yml"
|
||
}
|
||
|
||
# -- Step 4: Push files to repo --
|
||
Log-Step "Step 4/8: Pushing scaffold files to repository..."
|
||
if ($DryRun) {
|
||
Log-Warn "[DRY RUN] Would git add/commit/push to $repoUrl"
|
||
} else {
|
||
Push-Location $workDir
|
||
try {
|
||
$commitMsg = "chore: initialize project scaffold`n`n- Add README.md with getting-started guide`n- Add MIT LICENSE`n- Add CONTRIBUTING.md with guidelines`n- Add .gitlink-ci.yml CI pipeline configuration"
|
||
git add README.md LICENSE CONTRIBUTING.md .gitlink-ci.yml 2>&1 | Out-Null
|
||
git -c user.name="$Owner" -c user.email="$Owner@gitlink.org.cn" commit -m $commitMsg 2>&1 | Select-Object -Last 1
|
||
git push -u origin master 2>&1 | Select-Object -Last 1
|
||
Log-Ok "Scaffold files pushed to master"
|
||
} finally {
|
||
Pop-Location
|
||
}
|
||
}
|
||
|
||
# -- Step 5: Create Milestones --
|
||
Log-Step "Step 5/8: Creating initial milestone..."
|
||
|
||
$milestones = @(
|
||
@{ Name = "v1.0.0 - First Release"; Description = "First official release milestone" }
|
||
)
|
||
|
||
if ($DryRun) {
|
||
Log-Warn "[DRY RUN] Would create $($milestones.Count) milestones"
|
||
} else {
|
||
foreach ($ms in $milestones) {
|
||
$msResult = Invoke-GL "milestone", "+create", "--owner", $Owner, "--repo", $Name, "--name", $ms.Name, "--description", $ms.Description
|
||
if ($msResult) {
|
||
try {
|
||
$msJson = $msResult | ConvertFrom-Json
|
||
if ($msJson.ok) {
|
||
Log-Ok "Milestone created: $($ms.Name)"
|
||
} else {
|
||
Log-Warn "Milestone creation failed: $($ms.Name)"
|
||
}
|
||
} catch {
|
||
Log-Warn "Milestone creation may have failed: $($ms.Name)"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
# -- Step 6: Create Initial Issues --
|
||
Log-Step "Step 6/8: Creating welcome issue..."
|
||
|
||
$issuesToCreate = @(
|
||
@{ Title = "Welcome to $Name"; Body = "欢迎来到 **${Name}** 的仓库,这是本仓库的第一条issue!!"; Label = "welcome" }
|
||
)
|
||
|
||
if ($DryRun) {
|
||
Log-Warn "[DRY RUN] Would create $($issuesToCreate.Count) initial issues"
|
||
} else {
|
||
foreach ($entry in $issuesToCreate) {
|
||
$issueResult = Invoke-GL "issue", "+create", "--owner", $Owner, "--repo", $Name, "--title", $entry.Title, "--body", $entry.Body
|
||
if ($issueResult) {
|
||
try {
|
||
$issueJson = $issueResult | ConvertFrom-Json
|
||
$issueNum = if ($issueJson.ok -and $issueJson.data.id) { $issueJson.data.id } elseif ($issueJson.ok -and $issueJson.data.number) { $issueJson.data.number } else { $null }
|
||
if ($issueNum) {
|
||
Invoke-GL "issue", "+label-add", "--owner", $Owner, "--repo", $Name, "--number", $issueNum, "--labels", $entry.Label | Out-Null
|
||
Log-Ok "Issue created: #$issueNum - $($entry.Title)"
|
||
}
|
||
} catch {
|
||
Log-Warn "Issue creation may have failed: $($entry.Title)"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
# -- Step 7: Protect Default Branch --
|
||
Log-Step "Step 7/8: Protecting master branch..."
|
||
if ($DryRun) {
|
||
Log-Warn "[DRY RUN] Would protect branch 'master'"
|
||
} else {
|
||
$protectResult = Invoke-GL "branch", "+protect", "--owner", $Owner, "--repo", $Name, "--name", "master"
|
||
if ($protectResult) {
|
||
try {
|
||
$protectJson = $protectResult | ConvertFrom-Json
|
||
if ($protectJson.ok) {
|
||
Log-Ok "Branch 'master' protected"
|
||
} else {
|
||
Log-Warn "Branch protection may have failed (may require admin permissions)"
|
||
}
|
||
} catch {
|
||
Log-Warn "Branch protection may have failed (may require admin permissions)"
|
||
}
|
||
}
|
||
}
|
||
|
||
# -- Step 8: Create Initial Release --
|
||
Log-Step "Step 8/8: Creating initial release v0.1.0..."
|
||
|
||
$releaseBody = @"
|
||
# v0.1.0 - Initial Release
|
||
|
||
## What's New
|
||
- Project initialized with $Lang template
|
||
- README, LICENSE, CONTRIBUTING guide in repository
|
||
- CI/CD pipeline configuration (`.gitlink-ci.yml`)
|
||
- $($milestones.Count) project milestone created
|
||
- $($issuesToCreate.Count) 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 ($DryRun) {
|
||
Log-Warn "[DRY RUN] Would create release v0.1.0"
|
||
} else {
|
||
$releaseResult = Invoke-GL "release", "+create", "--owner", $Owner, "--repo", $Name, "--tag", "v0.1.0", "--name", "Initial Release", "--body", $releaseBody
|
||
if ($releaseResult) {
|
||
try {
|
||
$releaseJson = $releaseResult | ConvertFrom-Json
|
||
if ($releaseJson.ok) {
|
||
Log-Ok "Release v0.1.0 created"
|
||
} else {
|
||
Log-Warn "Release creation may have failed"
|
||
}
|
||
} catch {
|
||
Log-Warn "Release creation may have failed"
|
||
}
|
||
}
|
||
}
|
||
|
||
# ----------------------------------------------------------------
|
||
Log-Title "Project Initialization Complete"
|
||
# ----------------------------------------------------------------
|
||
|
||
Write-Host " Repository: $Owner/$Name" -ForegroundColor Green
|
||
Write-Host " Files: README.md, LICENSE, CONTRIBUTING.md, .gitlink-ci.yml" -ForegroundColor Green
|
||
Write-Host " Milestones: $($milestones.Count) milestone" -ForegroundColor Green
|
||
Write-Host " Issues: $($issuesToCreate.Count) initial issues" -ForegroundColor Green
|
||
Write-Host " Branch: master (protected)" -ForegroundColor Green
|
||
Write-Host " Release: v0.1.0" -ForegroundColor Green
|
||
Write-Host ""
|
||
Write-Host "Next steps:" -ForegroundColor Cyan
|
||
Write-Host " 1. Clone: git clone $repoUrl"
|
||
Write-Host " 2. Start coding and close the first issue"
|
||
Write-Host " 3. CI/CD will trigger on your first push"
|
||
|
||
# Cleanup temp directory
|
||
if (-not $DryRun -and (Test-Path $workDir)) {
|
||
Remove-Item -Recurse -Force $workDir -ErrorAction SilentlyContinue
|
||
}
|