• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CyberDuck79 / duckfile / 17276797710

27 Aug 2025 07:32PM UTC coverage: 72.988% (+0.5%) from 72.489%
17276797710

Pull #54

github

CyberDuck79
feat(run): refactor monolithic run.go into focused components

- Split run.go into: paths, remote (fetch + decision), render, link, exec, target, variables, checksum, commit_hash, sync, clean
- Introduce remote fetch decision (decideRemoteFetch) and modular ensureRendered/linkRendered/pruneOldRendered
- Add dedicated test files: render_test, link_test, exec_test, remote_fetch_test, remote_decision_test, sync_pipeline_test, checksum_test, commit_hash_test, variables_test, clean_test, paths_test, unit_test (misc)
- Remove legacy run_* test files with migrated coverage
- Maintain existing behavior (no functional CLI changes); improved test isolation and maintainability

Refs: architecture discussion in PR description
Pull Request #54: feat(run): refactor run package & split tests

395 of 471 new or added lines in 11 files covered. (83.86%)

1197 of 1640 relevant lines covered (72.99%)

10.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.67
/internal/run/commit_hash.go
1
package run
2

3
import (
4
        "fmt"
5
        "os"
6
        "path/filepath"
7
        "strings"
8

9
        "github.com/CyberDuck79/duckfile/internal/log"
10
)
11

12
// writeCommitHashMetadata stores the commit hash in the cache directory
13
func writeCommitHashMetadata(objDir, commitHash string) error {
26✔
14
        if commitHash == "" {
28✔
15
                return nil // Nothing to write
2✔
16
        }
2✔
17

18
        metadataFile := filepath.Join(objDir, "commit.hash")
24✔
19
        return os.WriteFile(metadataFile, []byte(commitHash), 0o644)
24✔
20
}
21

22
// readCommitHashMetadata reads the commit hash from the cache directory
23
func readCommitHashMetadata(objDir string) (string, error) {
26✔
24
        metadataFile := filepath.Join(objDir, "commit.hash")
26✔
25

26✔
26
        data, err := os.ReadFile(metadataFile)
26✔
27
        if err != nil {
29✔
28
                if os.IsNotExist(err) {
6✔
29
                        return "", nil // No metadata file exists
3✔
30
                }
3✔
NEW
31
                return "", fmt.Errorf("failed to read commit hash metadata: %w", err)
×
32
        }
33

34
        commitHash := strings.TrimSpace(string(data))
23✔
35
        return commitHash, nil
23✔
36
}
37

38
// hasCommitHashMetadata checks if commit hash metadata exists in the cache directory
39
func hasCommitHashMetadata(objDir string) bool {
7✔
40
        metadataFile := filepath.Join(objDir, "commit.hash")
7✔
41
        _, err := os.Stat(metadataFile)
7✔
42
        return err == nil
7✔
43
}
7✔
44

45
// validateCachedCommitHash checks if the cached commit hash is still valid by comparing with remote.
46
// Returns true if cache is valid, false if it should be invalidated, and an error for network issues.
47
func validateCachedCommitHash(repo, ref, objDir string) (bool, error) {
16✔
48
        // Read stored commit hash
16✔
49
        storedHash, err := readCommitHashMetadata(objDir)
16✔
50
        if err != nil {
16✔
NEW
51
                return false, fmt.Errorf("failed to read cached commit hash: %w", err)
×
NEW
52
        }
×
53

54
        if storedHash == "" {
17✔
55
                // No stored hash means cache was created without commit tracking
1✔
56
                log.Debugf("no stored commit hash found for %s@%s, cache validation skipped", repo, ref)
1✔
57
                return true, nil
1✔
58
        }
1✔
59

60
        log.Debugf("validating cached commit hash %s for %s@%s", truncateHash(storedHash), repo, ref)
15✔
61

15✔
62
        // Get current remote commit hash
15✔
63
        remoteHash, err := getRemoteCommitFunc(repo, ref)
15✔
64
        if err != nil {
18✔
65
                // Network failure or repository error - warn but don't fail
3✔
66
                log.Warnf("failed to fetch remote commit hash for %s@%s validation: %v", repo, ref, err)
3✔
67
                log.Warnf("continuing with cached template (network error)")
3✔
68
                return true, nil
3✔
69
        }
3✔
70

71
        if storedHash == remoteHash {
16✔
72
                log.Debugf("✅ commit hash unchanged for %s@%s: %s", repo, ref, truncateHash(storedHash))
4✔
73
                return true, nil
4✔
74
        }
4✔
75

76
        log.Infof("🔄 commit hash changed for %s@%s: %s -> %s", repo, ref, truncateHash(storedHash), truncateHash(remoteHash))
8✔
77
        return false, nil
8✔
78
}
79

80
// invalidateCache removes the cached object to force re-rendering
81
func invalidateCache(objDir string) error {
5✔
82
        if err := os.RemoveAll(objDir); err != nil {
5✔
NEW
83
                return fmt.Errorf("failed to invalidate cache directory %s: %w", objDir, err)
×
NEW
84
        }
×
85
        log.Infof("❌ cache invalidated: %s", objDir)
5✔
86
        return nil
5✔
87
}
88

89
// truncateHash returns a shortened version of a commit hash for display purposes
90
func truncateHash(hash string) string {
41✔
91
        if len(hash) <= 12 {
47✔
92
                return hash
6✔
93
        }
6✔
94
        return hash[:12]
35✔
95
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc