summaryrefslogtreecommitdiff
path: root/internal/sync
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-10-31 20:13:32 +0200
committerPaul Buetow <paul@buetow.org>2025-10-31 20:13:32 +0200
commit11eea6a82cbfdde40ec1457c6ea080da4da6b7dc (patch)
tree8026068f6a3beb3ee02c45f06f4487f4b89caaf1 /internal/sync
parent5c3e0b5cf99d028c4f06be7a825388b296e37a22 (diff)
feat: implement amp AI tool support and replace Taskfile with Magev0.10.0
- Add amp as default AI tool for release notes and showcase generation - Fallback chain: amp → hexai → claude → aichat - Replace Taskfile.yaml with magefile.go for build automation - Update all documentation (README.md, AGENTS.md, doc/development.md) - Update version to 0.10.0 Amp-Thread-ID: https://ampcode.com/threads/T-735ba1e2-0255-4b43-8ed1-6c0d2f78301b Co-authored-by: Amp <amp@ampcode.com>
Diffstat (limited to 'internal/sync')
-rw-r--r--internal/sync/branch_analyzer.go94
-rw-r--r--internal/sync/branch_filter.go8
-rw-r--r--internal/sync/branch_sync.go12
-rw-r--r--internal/sync/git_operations.go22
-rw-r--r--internal/sync/repository_setup.go14
-rw-r--r--internal/sync/sync.go40
6 files changed, 95 insertions, 95 deletions
diff --git a/internal/sync/branch_analyzer.go b/internal/sync/branch_analyzer.go
index 3038fcc..7499996 100644
--- a/internal/sync/branch_analyzer.go
+++ b/internal/sync/branch_analyzer.go
@@ -12,28 +12,28 @@ import (
// BranchInfo holds information about a branch
type BranchInfo struct {
- Name string
- LastCommit time.Time
- Remote string
- IsAbandoned bool
- AbandonReason string
+ Name string
+ LastCommit time.Time
+ Remote string
+ IsAbandoned bool
+ AbandonReason string
RemotesWithBranch []string // List of remotes that have this branch
}
// AbandonedBranchReport holds the analysis results
type AbandonedBranchReport struct {
- MainBranchUpdated bool
- MainBranchLastCommit time.Time
- AbandonedBranches []BranchInfo
+ MainBranchUpdated bool
+ MainBranchLastCommit time.Time
+ AbandonedBranches []BranchInfo
AbandonedIgnoredBranches []BranchInfo // Abandoned branches that match exclusion patterns
- TotalBranches int
- TotalIgnoredBranches int
+ TotalBranches int
+ TotalIgnoredBranches int
}
// analyzeAbandonedBranches analyzes branches to find abandoned ones
func (s *Syncer) analyzeAbandonedBranches() (*AbandonedBranchReport, error) {
report := &AbandonedBranchReport{
- AbandonedBranches: []BranchInfo{},
+ AbandonedBranches: []BranchInfo{},
AbandonedIgnoredBranches: []BranchInfo{},
}
@@ -42,11 +42,11 @@ func (s *Syncer) analyzeAbandonedBranches() (*AbandonedBranchReport, error) {
if err != nil {
return nil, fmt.Errorf("failed to get branches: %w", err)
}
-
+
// Filter branches based on exclusion patterns
branches := s.branchFilter.FilterBranches(allBranches)
report.TotalBranches = len(branches)
-
+
// Get excluded branches for separate analysis
excludedBranches := s.branchFilter.GetExcludedBranches(allBranches)
report.TotalIgnoredBranches = len(excludedBranches)
@@ -69,7 +69,7 @@ func (s *Syncer) analyzeAbandonedBranches() (*AbandonedBranchReport, error) {
// Analyze each branch
sixMonthsAgo := time.Now().AddDate(0, -6, 0)
-
+
for _, branch := range branches {
// Skip main/master branches
if branch == "main" || branch == "master" {
@@ -89,7 +89,7 @@ func (s *Syncer) analyzeAbandonedBranches() (*AbandonedBranchReport, error) {
report.AbandonedBranches = append(report.AbandonedBranches, *branchInfo)
}
}
-
+
// Also analyze ignored branches for abandonment
for _, branch := range excludedBranches {
// Skip main/master branches even if they match exclusion patterns
@@ -127,7 +127,7 @@ func (s *Syncer) findMainBranch(branches []string) string {
// getBranchInfo gets information about a specific branch
func (s *Syncer) getBranchInfo(branch string) (*BranchInfo, error) {
info := &BranchInfo{
- Name: branch,
+ Name: branch,
RemotesWithBranch: []string{},
}
@@ -137,18 +137,18 @@ func (s *Syncer) getBranchInfo(branch string) (*BranchInfo, error) {
for i := range s.config.Organizations {
org := &s.config.Organizations[i]
-
+
// Skip backup locations if backup is not enabled
if org.BackupLocation && !s.backupEnabled {
continue
}
-
+
remoteName := s.getRemoteName(org)
if s.remoteBranchExists(remoteName, branch) {
// Add this remote to the list
info.RemotesWithBranch = append(info.RemotesWithBranch, remoteName)
-
+
// Get last commit date for this branch on this remote
commitTime, err := s.getLastCommitTime(remoteName, branch)
if err == nil && (latestCommit.IsZero() || commitTime.After(latestCommit)) {
@@ -211,22 +211,22 @@ func formatAbandonedBranchReport(report *AbandonedBranchReport, repoName string)
var sb strings.Builder
sb.WriteString(fmt.Sprintf("\nšŸ” Abandoned branches in %s:\n", repoName))
sb.WriteString(fmt.Sprintf(" Main branch last updated: %s\n", report.MainBranchLastCommit.Format("2006-01-02")))
-
+
if len(report.AbandonedBranches) > 0 {
sb.WriteString(fmt.Sprintf(" Found %d abandoned branches (no commits for 6+ months):\n\n", len(report.AbandonedBranches)))
for _, branch := range report.AbandonedBranches {
- sb.WriteString(fmt.Sprintf(" - %s (last commit: %s, %s)\n",
- branch.Name,
+ sb.WriteString(fmt.Sprintf(" - %s (last commit: %s, %s)\n",
+ branch.Name,
branch.LastCommit.Format("2006-01-02"),
branch.AbandonReason))
}
}
-
+
if len(report.AbandonedIgnoredBranches) > 0 {
sb.WriteString(fmt.Sprintf("\n Found %d abandoned IGNORED branches (no commits for 6+ months):\n\n", len(report.AbandonedIgnoredBranches)))
for _, branch := range report.AbandonedIgnoredBranches {
- sb.WriteString(fmt.Sprintf(" - %s (last commit: %s, %s)\n",
- branch.Name,
+ sb.WriteString(fmt.Sprintf(" - %s (last commit: %s, %s)\n",
+ branch.Name,
branch.LastCommit.Format("2006-01-02"),
branch.AbandonReason))
}
@@ -244,7 +244,7 @@ func (s *Syncer) GenerateAbandonedBranchSummary() string {
totalAbandoned := 0
totalAbandonedIgnored := 0
reposWithAbandoned := 0
-
+
for _, report := range s.abandonedReports {
if len(report.AbandonedBranches) > 0 || len(report.AbandonedIgnoredBranches) > 0 {
totalAbandoned += len(report.AbandonedBranches)
@@ -274,30 +274,30 @@ func (s *Syncer) GenerateAbandonedBranchSummary() string {
if len(report.AbandonedBranches) == 0 && len(report.AbandonedIgnoredBranches) == 0 {
continue
}
-
+
totalBranches := len(report.AbandonedBranches) + len(report.AbandonedIgnoredBranches)
sb.WriteString(fmt.Sprintf("šŸ“ %s (%d branches):\n", repoName, totalBranches))
-
+
// Regular abandoned branches
if len(report.AbandonedBranches) > 0 {
sb.WriteString(" Regular branches:\n")
for _, branch := range report.AbandonedBranches {
- sb.WriteString(fmt.Sprintf(" - %s (last commit: %s)\n",
- branch.Name,
+ sb.WriteString(fmt.Sprintf(" - %s (last commit: %s)\n",
+ branch.Name,
branch.LastCommit.Format("2006-01-02")))
}
}
-
+
// Ignored abandoned branches
if len(report.AbandonedIgnoredBranches) > 0 {
sb.WriteString(" Ignored branches:\n")
for _, branch := range report.AbandonedIgnoredBranches {
- sb.WriteString(fmt.Sprintf(" - %s (last commit: %s)\n",
- branch.Name,
+ sb.WriteString(fmt.Sprintf(" - %s (last commit: %s)\n",
+ branch.Name,
branch.LastCommit.Format("2006-01-02")))
}
}
-
+
sb.WriteString("\n")
}
@@ -324,7 +324,7 @@ func (s *Syncer) GenerateDeleteCommands(report *AbandonedBranchReport, repoName
sb.WriteString("# === REGULAR BRANCHES ===\n")
for _, branch := range report.AbandonedBranches {
sb.WriteString(fmt.Sprintf("# Branch: %s (last commit: %s)\n", branch.Name, branch.LastCommit.Format("2006-01-02")))
-
+
// Delete from all remotes that have this branch
if len(branch.RemotesWithBranch) > 0 {
sb.WriteString("# Delete from remotes:\n")
@@ -332,19 +332,19 @@ func (s *Syncer) GenerateDeleteCommands(report *AbandonedBranchReport, repoName
sb.WriteString(fmt.Sprintf("git push %s --delete %s\n", remote, branch.Name))
}
}
-
+
// Delete local branch
sb.WriteString("# Delete local branch:\n")
sb.WriteString(fmt.Sprintf("git branch -D %s\n\n", branch.Name))
}
}
-
+
// Process ignored abandoned branches
if len(report.AbandonedIgnoredBranches) > 0 {
sb.WriteString("# === IGNORED BRANCHES ===\n")
for _, branch := range report.AbandonedIgnoredBranches {
sb.WriteString(fmt.Sprintf("# Branch: %s (last commit: %s) [IGNORED]\n", branch.Name, branch.LastCommit.Format("2006-01-02")))
-
+
// Delete from all remotes that have this branch
if len(branch.RemotesWithBranch) > 0 {
sb.WriteString("# Delete from remotes:\n")
@@ -352,7 +352,7 @@ func (s *Syncer) GenerateDeleteCommands(report *AbandonedBranchReport, repoName
sb.WriteString(fmt.Sprintf("git push %s --delete %s\n", remote, branch.Name))
}
}
-
+
// Delete local branch
sb.WriteString("# Delete local branch:\n")
sb.WriteString(fmt.Sprintf("git branch -D %s\n\n", branch.Name))
@@ -375,7 +375,7 @@ func (s *Syncer) GenerateDeleteScript() (string, error) {
totalAbandoned += len(report.AbandonedBranches)
totalIgnored += len(report.AbandonedIgnoredBranches)
}
-
+
if totalAbandoned == 0 && totalIgnored == 0 {
return "", nil
}
@@ -540,7 +540,7 @@ func (s *Syncer) GenerateDeleteScript() (string, error) {
fmt.Fprintf(file, " fi\n")
fmt.Fprintf(file, "else\n")
fmt.Fprintf(file, " echo \" šŸ”ø Deleting branch: %s (last commit: %s)\"\n", branch.Name, branch.LastCommit.Format("2006-01-02"))
-
+
// Check if we're on the branch to be deleted, and switch to main/master if so
fmt.Fprintf(file, " # Check if we're on the branch to be deleted\n")
fmt.Fprintf(file, " current_branch=$(git branch --show-current)\n")
@@ -558,12 +558,12 @@ func (s *Syncer) GenerateDeleteScript() (string, error) {
fmt.Fprintf(file, " if [[ \"$current_branch\" == \"%s\" ]] && [[ -z \"$main_branch\" ]]; then\n", branch.Name)
fmt.Fprintf(file, " continue\n")
fmt.Fprintf(file, " fi\n")
-
+
// Delete from remotes
for _, remote := range branch.RemotesWithBranch {
fmt.Fprintf(file, " execute_cmd git push %s --delete \"%s\"\n", remote, branch.Name)
}
-
+
// Delete local branch
fmt.Fprintf(file, " execute_cmd git branch -D \"%s\"\n", branch.Name)
fmt.Fprintf(file, "fi\n\n")
@@ -580,7 +580,7 @@ func (s *Syncer) GenerateDeleteScript() (string, error) {
fmt.Fprintf(file, " fi\n")
fmt.Fprintf(file, "else\n")
fmt.Fprintf(file, " echo \" šŸ”¹ Deleting ignored branch: %s (last commit: %s)\"\n", branch.Name, branch.LastCommit.Format("2006-01-02"))
-
+
// Check if we're on the branch to be deleted, and switch to main/master if so
fmt.Fprintf(file, " # Check if we're on the branch to be deleted\n")
fmt.Fprintf(file, " current_branch=$(git branch --show-current)\n")
@@ -598,12 +598,12 @@ func (s *Syncer) GenerateDeleteScript() (string, error) {
fmt.Fprintf(file, " if [[ \"$current_branch\" == \"%s\" ]] && [[ -z \"$main_branch\" ]]; then\n", branch.Name)
fmt.Fprintf(file, " continue\n")
fmt.Fprintf(file, " fi\n")
-
+
// Delete from remotes
for _, remote := range branch.RemotesWithBranch {
fmt.Fprintf(file, " execute_cmd git push %s --delete \"%s\"\n", remote, branch.Name)
}
-
+
// Delete local branch
fmt.Fprintf(file, " execute_cmd git branch -D \"%s\"\n", branch.Name)
fmt.Fprintf(file, "fi\n\n")
@@ -634,4 +634,4 @@ func (s *Syncer) GenerateDeleteScript() (string, error) {
}
return scriptPath, nil
-} \ No newline at end of file
+}
diff --git a/internal/sync/branch_filter.go b/internal/sync/branch_filter.go
index 3a4fd40..33f7895 100644
--- a/internal/sync/branch_filter.go
+++ b/internal/sync/branch_filter.go
@@ -77,7 +77,7 @@ func FormatExclusionReport(excludedBranches []string, patterns []string) string
var sb strings.Builder
sb.WriteString(fmt.Sprintf("\n🚫 Excluded %d branches based on patterns:\n", len(excludedBranches)))
-
+
// Show patterns
sb.WriteString(" Patterns: ")
for i, pattern := range patterns {
@@ -87,12 +87,12 @@ func FormatExclusionReport(excludedBranches []string, patterns []string) string
sb.WriteString(fmt.Sprintf("'%s'", pattern))
}
sb.WriteString("\n")
-
+
// Show excluded branches
sb.WriteString(" Excluded branches:\n")
for _, branch := range excludedBranches {
sb.WriteString(fmt.Sprintf(" - %s\n", branch))
}
-
+
return sb.String()
-} \ No newline at end of file
+}
diff --git a/internal/sync/branch_sync.go b/internal/sync/branch_sync.go
index 02f8964..eafb551 100644
--- a/internal/sync/branch_sync.go
+++ b/internal/sync/branch_sync.go
@@ -9,7 +9,7 @@ import (
// trackRemotesWithBranch finds which remotes have a specific branch
func (s *Syncer) trackRemotesWithBranch(branch string, remotes map[string]*config.Organization) map[string]bool {
remotesWithBranch := make(map[string]bool)
-
+
for remoteName, org := range remotes {
// Skip checking backup locations as we don't sync from them
if org.BackupLocation {
@@ -19,7 +19,7 @@ func (s *Syncer) trackRemotesWithBranch(branch string, remotes map[string]*confi
remotesWithBranch[remoteName] = true
}
}
-
+
return remotesWithBranch
}
@@ -29,14 +29,14 @@ func mergeFromRemotes(branch string, remotesWithBranch map[string]bool) error {
fmt.Printf(" Branch %s is local only, will push to all remotes\n", branch)
return nil
}
-
+
// Merge changes from all remotes that have this branch
for remoteName := range remotesWithBranch {
if err := mergeBranch(remoteName, branch); err != nil {
return err
}
}
-
+
return nil
}
@@ -56,7 +56,7 @@ func pushToAllRemotes(branch string, remotes map[string]*config.Organization, re
return err
}
}
-
+
return nil
}
@@ -69,4 +69,4 @@ func (s *Syncer) syncAllBranches(branches []string, remotes map[string]*config.O
}
}
return nil
-} \ No newline at end of file
+}
diff --git a/internal/sync/git_operations.go b/internal/sync/git_operations.go
index efa27f5..0bd698e 100644
--- a/internal/sync/git_operations.go
+++ b/internal/sync/git_operations.go
@@ -242,24 +242,24 @@ func createSSHBareRepository(sshHost, repoPath string) error {
if len(parts) != 2 {
return fmt.Errorf("invalid SSH host format: %s", sshHost)
}
-
+
userHost := parts[0]
basePath := parts[1]
-
+
// Full path to the repository
fullRepoPath := fmt.Sprintf("%s/%s.git", basePath, repoPath)
-
+
fmt.Printf("Creating bare repository at %s:%s\n", userHost, fullRepoPath)
-
+
// Create the repository directory and initialize as bare
commands := fmt.Sprintf("mkdir -p %s && cd %s && git init --bare", fullRepoPath, fullRepoPath)
cmd := exec.Command("ssh", userHost, commands)
output, err := cmd.CombinedOutput()
-
+
if err != nil {
return fmt.Errorf("failed to create bare repository: %w\n%s", err, string(output))
}
-
+
fmt.Printf("Successfully created bare repository at %s:%s\n", userHost, fullRepoPath)
return nil
}
@@ -280,18 +280,18 @@ func pushBranchWithBackupSupport(remoteName, branch string, remoteHasBranch bool
if err != nil {
return fmt.Errorf("failed to get remote URL: %w", err)
}
-
+
// Extract repo name from URL
repoName := extractRepoName(remoteURL)
if repoName == "" {
return fmt.Errorf("failed to extract repository name from URL: %s", remoteURL)
}
-
+
// Create the bare repository
if err := createSSHBareRepository(org.Host, repoName); err != nil {
return fmt.Errorf("failed to create SSH repository: %w", err)
}
-
+
// Try pushing again
cmd = exec.Command("git", "push", remoteName, branch, "--tags")
if err := cmd.Run(); err != nil {
@@ -300,7 +300,7 @@ func pushBranchWithBackupSupport(remoteName, branch string, remoteHasBranch bool
fmt.Printf(" Successfully pushed to newly created backup repository\n")
return nil
}
-
+
fmt.Printf(" Note: Remote repository %s does not exist - must be created manually\n", remoteName)
fmt.Printf(" Skipping push to %s\n", remoteName)
return nil // Not an error, just skip
@@ -341,7 +341,7 @@ func getRemoteURL(remoteName string) (string, error) {
func extractRepoName(url string) string {
// Remove .git suffix if present
url = strings.TrimSuffix(url, ".git")
-
+
// Extract the last component of the path
parts := strings.Split(url, "/")
if len(parts) > 0 {
diff --git a/internal/sync/repository_setup.go b/internal/sync/repository_setup.go
index 3ebafbd..7e2c40e 100644
--- a/internal/sync/repository_setup.go
+++ b/internal/sync/repository_setup.go
@@ -54,12 +54,12 @@ func (s *Syncer) setupNewRepository(repoPath string) error {
continue // Skip the first org we already cloned from
}
org := &s.config.Organizations[i]
-
+
// Skip backup locations if backup is not enabled
if org.BackupLocation && !s.backupEnabled {
continue
}
-
+
if err := s.addRemote(repoPath, org); err != nil {
return fmt.Errorf("failed to add remote %s: %w", s.getRemoteName(org), err)
}
@@ -75,12 +75,12 @@ func (s *Syncer) setupExistingRepository(repoPath string) error {
// Check and add any missing remotes
for i := range s.config.Organizations {
org := &s.config.Organizations[i]
-
+
// Skip backup locations if backup is not enabled
if org.BackupLocation && !s.backupEnabled {
continue
}
-
+
remoteName := s.getRemoteName(org)
// Check if remote exists
@@ -115,14 +115,14 @@ func (s *Syncer) getRemotesMap() map[string]*config.Organization {
remotes := make(map[string]*config.Organization)
for i := range s.config.Organizations {
org := &s.config.Organizations[i]
-
+
// Skip backup locations if backup is not enabled
if org.BackupLocation && !s.backupEnabled {
continue
}
-
+
remoteName := s.getRemoteName(org)
remotes[remoteName] = org
}
return remotes
-} \ No newline at end of file
+}
diff --git a/internal/sync/sync.go b/internal/sync/sync.go
index 0f51689..0f2f479 100644
--- a/internal/sync/sync.go
+++ b/internal/sync/sync.go
@@ -12,9 +12,9 @@ import (
// Syncer handles repository synchronization between organizations
type Syncer struct {
- config *config.Config
- workDir string
- repoName string
+ config *config.Config
+ workDir string
+ repoName string
abandonedReports map[string]*AbandonedBranchReport // Collects reports across repos
branchFilter *BranchFilter // Filter for excluding branches
backupEnabled bool // Whether to sync to backup locations
@@ -32,8 +32,8 @@ func New(cfg *config.Config, workDir string) *Syncer {
}
return &Syncer{
- config: cfg,
- workDir: workDir,
+ config: cfg,
+ workDir: workDir,
abandonedReports: make(map[string]*AbandonedBranchReport),
branchFilter: branchFilter,
backupEnabled: false, // Default to false, will be set via SetBackupEnabled
@@ -82,7 +82,7 @@ func (s *Syncer) SyncRepository(repoName string) error {
// Filter branches based on exclusion patterns
branches := s.branchFilter.FilterBranches(allBranches)
excludedBranches := s.branchFilter.GetExcludedBranches(allBranches)
-
+
// Report excluded branches if any
if exclusionReport := FormatExclusionReport(excludedBranches, s.config.ExcludeBranches); exclusionReport != "" {
fmt.Print(exclusionReport)
@@ -118,12 +118,12 @@ func (s *Syncer) SyncRepository(repoName string) error {
// This is used for showcase-only mode
func (s *Syncer) EnsureRepositoryCloned(repoName string) error {
s.repoName = repoName
-
+
// Create work directory if it doesn't exist
if err := os.MkdirAll(s.workDir, 0755); err != nil {
return fmt.Errorf("failed to create work directory: %w", err)
}
-
+
// Check if repository already exists
repoPath := filepath.Join(s.workDir, repoName)
if _, err := os.Stat(repoPath); err == nil {
@@ -131,10 +131,10 @@ func (s *Syncer) EnsureRepositoryCloned(repoName string) error {
fmt.Printf(" Repository %s already exists locally\n", repoName)
return nil
}
-
+
// Repository doesn't exist, clone it
fmt.Printf(" Cloning %s...\n", repoName)
-
+
// Find first non-backup organization to clone from
var sourceOrg *config.Organization
for i := range s.config.Organizations {
@@ -143,16 +143,16 @@ func (s *Syncer) EnsureRepositoryCloned(repoName string) error {
break
}
}
-
+
if sourceOrg == nil {
return fmt.Errorf("no non-backup organizations configured to clone from")
}
-
+
// Clone the repository
if err := s.cloneRepository(sourceOrg, repoPath); err != nil {
return fmt.Errorf("failed to clone repository: %w", err)
}
-
+
fmt.Printf(" Successfully cloned %s\n", repoName)
return nil
}
@@ -282,7 +282,7 @@ func (s *Syncer) syncBranch(branch string, remotes map[string]*config.Organizati
if stashed {
defer popStash()
}
-
+
// Create or checkout the branch
if err := s.checkoutBranch(branch); err != nil {
return fmt.Errorf("failed to checkout branch %s: %w", branch, err)
@@ -307,7 +307,7 @@ func (s *Syncer) handleWorkingDirectoryState() (bool, error) {
if err != nil || statusStr == "" {
return false, nil
}
-
+
if hasConflicts {
// Get absolute path for clarity
absPath, err := filepath.Abs(s.workDir)
@@ -316,7 +316,7 @@ func (s *Syncer) handleWorkingDirectoryState() (bool, error) {
}
return false, fmt.Errorf("repository has unresolved merge conflicts\nPlease resolve conflicts in: %s\nOr delete the directory to start fresh: rm -rf %s", absPath, absPath)
}
-
+
// If we have uncommitted changes but no conflicts, try to stash them
if err := stashChanges(); err != nil {
return false, fmt.Errorf("failed to stash changes: %w", err)
@@ -380,13 +380,13 @@ func (s *Syncer) getRemoteName(org *config.Organization) string {
func (s *Syncer) filterBackupBranches(output []byte) []byte {
lines := strings.Split(string(output), "\n")
var filtered []string
-
+
for _, line := range lines {
line = strings.TrimSpace(line)
if line == "" {
continue
}
-
+
// Check if this branch is from a backup remote
isBackup := false
for i := range s.config.Organizations {
@@ -399,11 +399,11 @@ func (s *Syncer) filterBackupBranches(output []byte) []byte {
}
}
}
-
+
if !isBackup {
filtered = append(filtered, line)
}
}
-
+
return []byte(strings.Join(filtered, "\n"))
}