pltr-cli 0.5.1__tar.gz → 0.5.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/PKG-INFO +1 -1
  2. pltr_cli-0.5.2/RELEASE.md +163 -0
  3. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/pyproject.toml +19 -6
  4. pltr_cli-0.5.2/scripts/release.py +371 -0
  5. pltr_cli-0.5.2/src/pltr/__init__.py +1 -0
  6. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/dataset.py +29 -130
  7. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/test_dataset_transactions.py +31 -29
  8. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/uv.lock +1 -1
  9. pltr_cli-0.5.1/scripts/release.py +0 -211
  10. pltr_cli-0.5.1/src/pltr/__init__.py +0 -1
  11. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/.github/workflows/ci.yml +0 -0
  12. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/.github/workflows/publish.yml +0 -0
  13. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/.github/workflows/test-publish.yml +0 -0
  14. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/.gitignore +0 -0
  15. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/.pre-commit-config.yaml +0 -0
  16. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/CHANGELOG.md +0 -0
  17. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/CLAUDE.md +0 -0
  18. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/LICENSE +0 -0
  19. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/README.md +0 -0
  20. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/children.csv +0 -0
  21. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/docs/README.md +0 -0
  22. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/docs/api/wrapper.md +0 -0
  23. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/docs/examples/csv-upload.md +0 -0
  24. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/docs/examples/gallery.md +0 -0
  25. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/docs/features/dataset-transactions.md +0 -0
  26. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/docs/user-guide/aliases.md +0 -0
  27. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/docs/user-guide/authentication.md +0 -0
  28. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/docs/user-guide/commands.md +0 -0
  29. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/docs/user-guide/quick-start.md +0 -0
  30. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/docs/user-guide/troubleshooting.md +0 -0
  31. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/docs/user-guide/workflows.md +0 -0
  32. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/folder_info.json +0 -0
  33. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/folders.json +0 -0
  34. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/mypy.ini +0 -0
  35. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/__main__.py +0 -0
  36. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/auth/__init__.py +0 -0
  37. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/auth/base.py +0 -0
  38. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/auth/manager.py +0 -0
  39. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/auth/oauth.py +0 -0
  40. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/auth/storage.py +0 -0
  41. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/auth/token.py +0 -0
  42. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/cli.py +0 -0
  43. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/__init__.py +0 -0
  44. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/admin.py +0 -0
  45. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/alias.py +0 -0
  46. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/completion.py +0 -0
  47. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/configure.py +0 -0
  48. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/connectivity.py +0 -0
  49. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/dataset.py +0 -0
  50. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/folder.py +0 -0
  51. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/mediasets.py +0 -0
  52. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/ontology.py +0 -0
  53. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/orchestration.py +0 -0
  54. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/project.py +0 -0
  55. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/resource.py +0 -0
  56. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/resource_role.py +0 -0
  57. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/shell.py +0 -0
  58. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/space.py +0 -0
  59. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/sql.py +0 -0
  60. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/commands/verify.py +0 -0
  61. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/config/__init__.py +0 -0
  62. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/config/aliases.py +0 -0
  63. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/config/profiles.py +0 -0
  64. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/config/settings.py +0 -0
  65. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/__init__.py +0 -0
  66. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/admin.py +0 -0
  67. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/base.py +0 -0
  68. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/connectivity.py +0 -0
  69. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/folder.py +0 -0
  70. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/mediasets.py +0 -0
  71. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/ontology.py +0 -0
  72. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/orchestration.py +0 -0
  73. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/project.py +0 -0
  74. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/resource.py +0 -0
  75. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/resource_role.py +0 -0
  76. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/space.py +0 -0
  77. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/services/sql.py +0 -0
  78. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/utils/__init__.py +0 -0
  79. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/utils/alias_resolver.py +0 -0
  80. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/utils/completion.py +0 -0
  81. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/utils/formatting.py +0 -0
  82. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/src/pltr/utils/progress.py +0 -0
  83. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/__init__.py +0 -0
  84. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/conftest.py +0 -0
  85. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/integration/README.md +0 -0
  86. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/integration/__init__.py +0 -0
  87. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/integration/conftest.py +0 -0
  88. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/integration/test_auth_flow.py +0 -0
  89. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/integration/test_cli_integration.py +0 -0
  90. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/integration/test_data_workflows.py +0 -0
  91. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/integration/test_data_workflows_simple.py +0 -0
  92. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/integration/test_simple_integration.py +0 -0
  93. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_auth/__init__.py +0 -0
  94. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_auth/test_base.py +0 -0
  95. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_auth/test_manager.py +0 -0
  96. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_auth/test_oauth.py +0 -0
  97. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_auth/test_storage.py +0 -0
  98. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_auth/test_token.py +0 -0
  99. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_commands/__init__.py +0 -0
  100. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_commands/test_admin.py +0 -0
  101. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_commands/test_alias.py +0 -0
  102. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_commands/test_completion.py +0 -0
  103. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_commands/test_connectivity.py +0 -0
  104. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_commands/test_dataset.py +0 -0
  105. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_commands/test_folder.py +0 -0
  106. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_commands/test_ontology.py +0 -0
  107. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_commands/test_orchestration.py +0 -0
  108. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_commands/test_shell.py +0 -0
  109. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_commands/test_sql.py +0 -0
  110. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_commands/test_verify_simple.py +0 -0
  111. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_config/__init__.py +0 -0
  112. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_config/test_aliases.py +0 -0
  113. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_config/test_profiles.py +0 -0
  114. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_config/test_settings.py +0 -0
  115. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/__init__.py +0 -0
  116. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/test_admin.py +0 -0
  117. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/test_base.py +0 -0
  118. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/test_connectivity.py +0 -0
  119. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/test_dataset.py +0 -0
  120. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/test_folder.py +0 -0
  121. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/test_ontology.py +0 -0
  122. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/test_orchestration.py +0 -0
  123. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/test_project.py +0 -0
  124. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/test_resource.py +0 -0
  125. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/test_resource_role.py +0 -0
  126. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/test_space.py +0 -0
  127. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_services/test_sql.py +0 -0
  128. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_utils/__init__.py +0 -0
  129. {pltr_cli-0.5.1 → pltr_cli-0.5.2}/tests/test_utils/test_alias_resolver.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pltr-cli
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: Command-line interface for Palantir Foundry APIs
5
5
  Project-URL: Homepage, https://github.com/anjor/pltr-cli
6
6
  Project-URL: Repository, https://github.com/anjor/pltr-cli
@@ -0,0 +1,163 @@
1
+ # Release Process
2
+
3
+ This document describes how to create releases for pltr-cli using the automated release script.
4
+
5
+ ## Overview
6
+
7
+ The release script (`scripts/release.py`) supports both interactive and non-interactive modes to accommodate different use cases:
8
+ - **Interactive mode**: For human developers who want to review and confirm each step
9
+ - **Non-interactive mode**: For AI agents and automated systems that need to create releases programmatically
10
+
11
+ ## Quick Start
12
+
13
+ ### For Humans (Interactive Mode)
14
+
15
+ ```bash
16
+ # Patch release (0.5.1 → 0.5.2)
17
+ python scripts/release.py --type patch
18
+
19
+ # Minor release (0.5.1 → 0.6.0)
20
+ python scripts/release.py --type minor
21
+
22
+ # Major release (0.5.1 → 1.0.0)
23
+ python scripts/release.py --type major
24
+
25
+ # Specific version
26
+ python scripts/release.py --version 0.6.0
27
+ ```
28
+
29
+ ### For AI Agents/Automation (Non-Interactive Mode)
30
+
31
+ ```bash
32
+ # Create release without prompts, don't push
33
+ python scripts/release.py --version 0.5.2 --yes --no-push
34
+
35
+ # Create release and push automatically
36
+ python scripts/release.py --type patch --yes --push
37
+
38
+ # Test what would happen (dry run)
39
+ python scripts/release.py --version 0.5.2 --dry-run
40
+ ```
41
+
42
+ ## Command-Line Arguments
43
+
44
+ | Argument | Description |
45
+ |----------|-------------|
46
+ | `--version X.Y.Z` | Specify exact version to release |
47
+ | `--type {major\|minor\|patch}` | Bump version automatically |
48
+ | `--yes`, `-y` | Skip all confirmation prompts (non-interactive mode) |
49
+ | `--push` | Push to origin without asking (requires `--yes`) |
50
+ | `--no-push` | Don't push to origin (useful for testing) |
51
+ | `--dry-run` | Show what would be done without making changes |
52
+
53
+ ## What the Script Does
54
+
55
+ 1. **Validates environment**:
56
+ - Checks that you're in a git repository
57
+ - Ensures working directory is clean (no uncommitted changes)
58
+ - Validates version format
59
+
60
+ 2. **Version handling**:
61
+ - Gets current version from `pyproject.toml`
62
+ - Calculates or validates new version
63
+ - Warns if version already exists or is the same as current
64
+
65
+ 3. **Creates release**:
66
+ - Updates version in `pyproject.toml`
67
+ - Creates git commit with message like "patch: Release version 0.5.2"
68
+ - Creates git tag like "v0.5.2"
69
+
70
+ 4. **Optional push**:
71
+ - Pushes commit and tag to origin (triggers GitHub Actions)
72
+ - Can be automatic (`--push`), skipped (`--no-push`), or prompted (default)
73
+
74
+ ## Usage Examples
75
+
76
+ ### Interactive Development Workflow
77
+ ```bash
78
+ # Make your changes
79
+ git add .
80
+ git commit -m "feat: add new feature"
81
+
82
+ # Create a patch release interactively
83
+ python scripts/release.py --type patch
84
+ # → Script will prompt for confirmation
85
+ # → Script will ask if you want to push
86
+
87
+ # The script will:
88
+ # 1. Update pyproject.toml (0.5.1 → 0.5.2)
89
+ # 2. Create commit "patch: Release version 0.5.2"
90
+ # 3. Create tag "v0.5.2"
91
+ # 4. Ask if you want to push to trigger publishing
92
+ ```
93
+
94
+ ### AI Agent Workflow
95
+ ```bash
96
+ # AI agent creates a release without any prompts
97
+ python scripts/release.py --version 0.5.2 --yes --no-push
98
+
99
+ # The script will:
100
+ # 1. Update pyproject.toml to version 0.5.2
101
+ # 2. Create commit "release: Release version 0.5.2"
102
+ # 3. Create tag "v0.5.2"
103
+ # 4. NOT push (--no-push specified)
104
+ # 5. Print instructions for manual push if needed
105
+ ```
106
+
107
+ ### Testing/Validation Workflow
108
+ ```bash
109
+ # See what would happen without making changes
110
+ python scripts/release.py --version 0.6.0 --dry-run
111
+
112
+ # Create release locally but don't push (for testing)
113
+ python scripts/release.py --version 0.6.0 --yes --no-push
114
+ ```
115
+
116
+ ## GitHub Actions Integration
117
+
118
+ When commits and tags are pushed to the repository, GitHub Actions will automatically:
119
+ 1. Build the package
120
+ 2. Run tests
121
+ 3. Publish to PyPI (for tagged releases)
122
+ 4. Create GitHub release with release notes
123
+
124
+ Monitor the workflow at: https://github.com/anjor/pltr-cli/actions
125
+
126
+ ## Error Handling
127
+
128
+ The script handles several common error scenarios:
129
+
130
+ - **Dirty working directory**: Script will fail if there are uncommitted changes
131
+ - **Duplicate versions**: Warns if trying to release the same version as current
132
+ - **Existing tags**: Warns if git tag already exists locally or remotely
133
+ - **Invalid versions**: Validates semantic version format (X.Y.Z)
134
+ - **Missing arguments**: Requires either `--version` or `--type`
135
+ - **Invalid combinations**: Prevents conflicting flags like `--push` and `--no-push`
136
+
137
+ ## Troubleshooting
138
+
139
+ ### "EOFError: EOF when reading a line"
140
+ This happens when running the script in non-interactive mode without the `--yes` flag. Add `--yes` to skip prompts.
141
+
142
+ ### "Tag already exists"
143
+ The script will warn you and ask for confirmation. You can:
144
+ - Delete the existing tag: `git tag -d v0.5.2`
145
+ - Use a different version number
146
+ - Continue anyway (not recommended)
147
+
148
+ ### "Working directory is not clean"
149
+ Commit or stash your changes before running the release script:
150
+ ```bash
151
+ git add .
152
+ git commit -m "your changes"
153
+ # OR
154
+ git stash
155
+ ```
156
+
157
+ ## Best Practices
158
+
159
+ 1. **Always test with `--dry-run` first** when trying new version numbers
160
+ 2. **Use `--no-push` for testing** to avoid accidental pushes
161
+ 3. **Follow semantic versioning**: patch for bug fixes, minor for features, major for breaking changes
162
+ 4. **Keep working directory clean** before creating releases
163
+ 5. **Monitor GitHub Actions** after pushing to ensure successful publishing
@@ -1,12 +1,11 @@
1
1
  [project]
2
2
  name = "pltr-cli"
3
- version = "0.5.1"
3
+ version = "0.5.2"
4
4
  description = "Command-line interface for Palantir Foundry APIs"
5
5
  authors = [
6
- { name = "anjor", email = "anjor@umd.edu" }
6
+ { name = "anjor", email = "anjor@umd.edu" },
7
7
  ]
8
8
  readme = "README.md"
9
- license = { text = "MIT" }
10
9
  requires-python = ">=3.9"
11
10
  dependencies = [
12
11
  "click-repl>=0.3.0",
@@ -17,7 +16,14 @@ dependencies = [
17
16
  "rich>=14.1.0",
18
17
  "typer>=0.16.0",
19
18
  ]
20
- keywords = ["palantir", "foundry", "cli", "api", "data", "ontology"]
19
+ keywords = [
20
+ "palantir",
21
+ "foundry",
22
+ "cli",
23
+ "api",
24
+ "data",
25
+ "ontology",
26
+ ]
21
27
  classifiers = [
22
28
  "Development Status :: 3 - Alpha",
23
29
  "Environment :: Console",
@@ -35,6 +41,9 @@ classifiers = [
35
41
  "Topic :: Utilities",
36
42
  ]
37
43
 
44
+ [project.license]
45
+ text = "MIT"
46
+
38
47
  [project.urls]
39
48
  Homepage = "https://github.com/anjor/pltr-cli"
40
49
  Repository = "https://github.com/anjor/pltr-cli"
@@ -46,11 +55,15 @@ Documentation = "https://github.com/anjor/pltr-cli/blob/main/README.md"
46
55
  pltr = "pltr.cli:app"
47
56
 
48
57
  [build-system]
49
- requires = ["hatchling"]
58
+ requires = [
59
+ "hatchling",
60
+ ]
50
61
  build-backend = "hatchling.build"
51
62
 
52
63
  [tool.hatch.build.targets.wheel]
53
- packages = ["src/pltr"]
64
+ packages = [
65
+ "src/pltr",
66
+ ]
54
67
 
55
68
  [dependency-groups]
56
69
  dev = [
@@ -0,0 +1,371 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Release script for pltr-cli
4
+
5
+ Usage:
6
+ # Interactive mode (for humans)
7
+ python scripts/release.py --version 0.1.1
8
+ python scripts/release.py --type patch
9
+
10
+ # Non-interactive mode (for AI agents/automation)
11
+ python scripts/release.py --version 0.1.1 --yes --no-push
12
+ python scripts/release.py --type patch --yes --push
13
+
14
+ # Dry run to see what would happen
15
+ python scripts/release.py --version 0.1.1 --dry-run
16
+
17
+ Flags:
18
+ --yes, -y Skip all confirmation prompts (non-interactive mode)
19
+ --push Push to origin without asking (requires --yes)
20
+ --no-push Don't push to origin (useful for testing)
21
+ --dry-run Show what would be done without making changes
22
+ """
23
+
24
+ import argparse
25
+ import re
26
+ import subprocess
27
+ import sys
28
+ import tomllib
29
+ import tomli_w
30
+ from pathlib import Path
31
+
32
+
33
+ def get_current_version():
34
+ """Get the current version from pyproject.toml"""
35
+ pyproject_path = Path("pyproject.toml")
36
+ if not pyproject_path.exists():
37
+ print("Error: pyproject.toml not found")
38
+ sys.exit(1)
39
+
40
+ with open(pyproject_path, "rb") as f:
41
+ config = tomllib.load(f)
42
+
43
+ return config["project"]["version"]
44
+
45
+
46
+ def update_version_in_pyproject(new_version):
47
+ """Update version in pyproject.toml"""
48
+ pyproject_path = Path("pyproject.toml")
49
+
50
+ with open(pyproject_path, "rb") as f:
51
+ config = tomllib.load(f)
52
+
53
+ config["project"]["version"] = new_version
54
+
55
+ with open(pyproject_path, "wb") as f:
56
+ tomli_w.dump(config, f)
57
+
58
+ print(f"Updated pyproject.toml version to {new_version}")
59
+
60
+
61
+ def update_version_in_init_py(new_version):
62
+ """Update __version__ in src/pltr/__init__.py"""
63
+ init_py_path = Path("src/pltr/__init__.py")
64
+
65
+ if not init_py_path.exists():
66
+ print("Error: src/pltr/__init__.py not found")
67
+ sys.exit(1)
68
+
69
+ # Read the current content
70
+ content = init_py_path.read_text()
71
+
72
+ # Update the version using regex
73
+ import re
74
+
75
+ pattern = r'__version__ = "[^"]+"'
76
+ replacement = f'__version__ = "{new_version}"'
77
+
78
+ if not re.search(pattern, content):
79
+ print("Error: Could not find __version__ in src/pltr/__init__.py")
80
+ sys.exit(1)
81
+
82
+ updated_content = re.sub(pattern, replacement, content)
83
+ init_py_path.write_text(updated_content)
84
+
85
+ print(f"Updated src/pltr/__init__.py __version__ to {new_version}")
86
+
87
+
88
+ def validate_version(version):
89
+ """Validate semantic version format"""
90
+ pattern = r"^\d+\.\d+\.\d+(?:-[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*)?$"
91
+ if not re.match(pattern, version):
92
+ print(
93
+ f"Error: Invalid version format '{version}'. Use semantic versioning (e.g., 1.0.0)"
94
+ )
95
+ sys.exit(1)
96
+
97
+
98
+ def run_git_command(cmd):
99
+ """Run git command and return result"""
100
+ try:
101
+ result = subprocess.run(
102
+ cmd, shell=True, check=True, capture_output=True, text=True
103
+ )
104
+ return result.stdout.strip()
105
+ except subprocess.CalledProcessError as e:
106
+ print(f"Error running git command: {cmd}")
107
+ print(f"Error output: {e.stderr}")
108
+ sys.exit(1)
109
+
110
+
111
+ def check_git_status():
112
+ """Check if git working directory is clean"""
113
+ status = run_git_command("git status --porcelain")
114
+ if status:
115
+ print(
116
+ "Error: Working directory is not clean. Please commit or stash changes first."
117
+ )
118
+ print("Uncommitted changes:")
119
+ print(status)
120
+ sys.exit(1)
121
+
122
+
123
+ def check_tag_exists(version):
124
+ """Check if a git tag already exists for this version"""
125
+ tag_name = f"v{version}"
126
+ try:
127
+ # Check if tag exists locally
128
+ result = subprocess.run(
129
+ ["git", "tag", "-l", tag_name], capture_output=True, text=True, check=True
130
+ )
131
+ if result.stdout.strip():
132
+ print(f"Warning: Tag {tag_name} already exists locally.")
133
+ return True
134
+ except subprocess.CalledProcessError:
135
+ pass
136
+
137
+ try:
138
+ # Check if tag exists on remote
139
+ result = subprocess.run(
140
+ ["git", "ls-remote", "--tags", "origin", tag_name],
141
+ capture_output=True,
142
+ text=True,
143
+ check=True,
144
+ )
145
+ if result.stdout.strip():
146
+ print(f"Warning: Tag {tag_name} already exists on remote.")
147
+ return True
148
+ except subprocess.CalledProcessError:
149
+ # Remote might not exist or be accessible, continue
150
+ pass
151
+
152
+ return False
153
+
154
+
155
+ def create_release_commit_and_tag(version, release_type, push_mode="ask"):
156
+ """Create release commit and tag"""
157
+ # Stage the version file changes
158
+ run_git_command("git add pyproject.toml src/pltr/__init__.py")
159
+
160
+ # Create release commit
161
+ commit_message = f"{release_type}: Release version {version}"
162
+ run_git_command(f'git commit -m "{commit_message}"')
163
+ print(f"Created release commit: {commit_message}")
164
+
165
+ # Create and push tag
166
+ tag_name = f"v{version}"
167
+ try:
168
+ run_git_command(f'git tag -a {tag_name} -m "Release {version}"')
169
+ print(f"Created tag: {tag_name}")
170
+ except SystemExit:
171
+ print(f"Error: Failed to create tag {tag_name}. It may already exist.")
172
+ print(f"To delete the existing tag: git tag -d {tag_name}")
173
+ print(f"To delete from remote: git push origin :refs/tags/{tag_name}")
174
+ raise
175
+
176
+ # Handle push based on mode
177
+ if push_mode == "force":
178
+ run_git_command("git push origin HEAD")
179
+ run_git_command(f"git push origin {tag_name}")
180
+ print("Pushed commit and tag to origin")
181
+ print("GitHub Actions will now build and publish the release automatically")
182
+ print("Monitor the workflow at: https://github.com/anjor/pltr-cli/actions")
183
+ elif push_mode == "no":
184
+ print("Not pushing to origin (--no-push specified).")
185
+ print("You can push manually later with:")
186
+ print(" git push origin HEAD")
187
+ print(f" git push origin {tag_name}")
188
+ else: # push_mode == "ask"
189
+ push_choice = (
190
+ input(f"Push commit and tag '{tag_name}' to origin? (y/N): ")
191
+ .strip()
192
+ .lower()
193
+ )
194
+ if push_choice in ["y", "yes"]:
195
+ run_git_command("git push origin HEAD")
196
+ run_git_command(f"git push origin {tag_name}")
197
+ print("Pushed commit and tag to origin")
198
+ print("GitHub Actions will now build and publish the release automatically")
199
+ print("Monitor the workflow at: https://github.com/anjor/pltr-cli/actions")
200
+ else:
201
+ print("Not pushing to origin. You can push manually later with:")
202
+ print(" git push origin HEAD")
203
+ print(f" git push origin {tag_name}")
204
+
205
+
206
+ def bump_version(current_version, bump_type):
207
+ """Bump version based on type"""
208
+ parts = current_version.split(".")
209
+ if len(parts) != 3:
210
+ print(
211
+ f"Error: Current version '{current_version}' is not in semantic version format"
212
+ )
213
+ sys.exit(1)
214
+
215
+ major, minor, patch = map(int, parts)
216
+
217
+ if bump_type == "major":
218
+ return f"{major + 1}.0.0"
219
+ elif bump_type == "minor":
220
+ return f"{major}.{minor + 1}.0"
221
+ elif bump_type == "patch":
222
+ return f"{major}.{minor}.{patch + 1}"
223
+ else:
224
+ print(f"Error: Invalid bump type '{bump_type}'. Use: major, minor, or patch")
225
+ sys.exit(1)
226
+
227
+
228
+ def main():
229
+ parser = argparse.ArgumentParser(description="Create a release for pltr-cli")
230
+ parser.add_argument("--version", help="Specific version to release (e.g., 1.0.0)")
231
+ parser.add_argument(
232
+ "--type",
233
+ choices=["major", "minor", "patch"],
234
+ help="Version bump type (alternative to --version)",
235
+ )
236
+ parser.add_argument(
237
+ "--dry-run",
238
+ action="store_true",
239
+ help="Show what would be done without making changes",
240
+ )
241
+ parser.add_argument(
242
+ "--yes",
243
+ "-y",
244
+ action="store_true",
245
+ help="Skip all confirmation prompts (non-interactive mode)",
246
+ )
247
+ parser.add_argument(
248
+ "--push",
249
+ action="store_true",
250
+ help="Push to origin without asking (requires --yes)",
251
+ )
252
+ parser.add_argument(
253
+ "--no-push",
254
+ action="store_true",
255
+ help="Don't push to origin (useful for testing)",
256
+ )
257
+
258
+ args = parser.parse_args()
259
+
260
+ # Validate argument combinations
261
+ if args.push and args.no_push:
262
+ print("Error: Cannot specify both --push and --no-push")
263
+ sys.exit(1)
264
+
265
+ if args.push and not args.yes:
266
+ print("Error: --push requires --yes (non-interactive mode)")
267
+ sys.exit(1)
268
+
269
+ # Ensure we're in a git repository
270
+ try:
271
+ run_git_command("git rev-parse --git-dir")
272
+ except subprocess.CalledProcessError:
273
+ print("Error: Not in a git repository")
274
+ sys.exit(1)
275
+
276
+ # Get current version
277
+ current_version = get_current_version()
278
+ print(f"Current version: {current_version}")
279
+
280
+ # Determine new version
281
+ if args.version and args.type:
282
+ print("Error: Cannot specify both --version and --type")
283
+ sys.exit(1)
284
+ elif args.version:
285
+ new_version = args.version
286
+ validate_version(new_version)
287
+ release_type = "release"
288
+ elif args.type:
289
+ new_version = bump_version(current_version, args.type)
290
+ release_type = args.type
291
+ else:
292
+ print("Error: Must specify either --version or --type")
293
+ sys.exit(1)
294
+
295
+ print(f"New version: {new_version}")
296
+
297
+ # Check if we're trying to release the same version
298
+ if new_version == current_version:
299
+ print(f"\nWarning: Version {new_version} is the same as current version.")
300
+ print("This will create a new commit and tag for the same version.")
301
+ if not args.yes:
302
+ confirm_same = input("Continue anyway? (y/N): ").strip().lower()
303
+ if confirm_same not in ["y", "yes"]:
304
+ print("Release cancelled")
305
+ sys.exit(0)
306
+
307
+ if args.dry_run:
308
+ print("\nDry run mode - would perform these actions:")
309
+ print(f"1. Update pyproject.toml version to {new_version}")
310
+ print(f"2. Update src/pltr/__init__.py __version__ to {new_version}")
311
+ print(f"3. Create git commit: '{release_type}: Release version {new_version}'")
312
+ print(f"4. Create git tag: v{new_version}")
313
+ print("5. Optionally push to origin")
314
+ return
315
+
316
+ # Check git status
317
+ check_git_status()
318
+
319
+ # Check if tag already exists
320
+ if check_tag_exists(new_version):
321
+ if not args.yes:
322
+ confirm_tag = (
323
+ input(f"Tag v{new_version} already exists. Continue anyway? (y/N): ")
324
+ .strip()
325
+ .lower()
326
+ )
327
+ if confirm_tag not in ["y", "yes"]:
328
+ print("Release cancelled")
329
+ sys.exit(0)
330
+ else:
331
+ print(f"Continuing despite existing tag v{new_version} (--yes specified)")
332
+
333
+ # Confirm release
334
+ print(f"\nAbout to create release {new_version}")
335
+ print("This will:")
336
+ print(f"1. Update pyproject.toml version to {new_version}")
337
+ print(f"2. Update src/pltr/__init__.py __version__ to {new_version}")
338
+ print(f"3. Create git commit and tag v{new_version}")
339
+ if args.push:
340
+ print("4. Push to origin to trigger GitHub Actions publishing")
341
+ elif args.no_push:
342
+ print("4. NOT push to origin (--no-push specified)")
343
+ else:
344
+ print("4. Optionally push to trigger GitHub Actions publishing")
345
+
346
+ if not args.yes:
347
+ confirm = input("\nProceed with release? (y/N): ").strip().lower()
348
+ if confirm not in ["y", "yes"]:
349
+ print("Release cancelled")
350
+ sys.exit(0)
351
+ else:
352
+ print("\nProceeding with release (--yes specified)...")
353
+
354
+ # Determine push mode
355
+ if args.push:
356
+ push_mode = "force"
357
+ elif args.no_push:
358
+ push_mode = "no"
359
+ else:
360
+ push_mode = "ask"
361
+
362
+ # Perform release
363
+ update_version_in_pyproject(new_version)
364
+ update_version_in_init_py(new_version)
365
+ create_release_commit_and_tag(new_version, release_type, push_mode)
366
+
367
+ print(f"\n✅ Release {new_version} created successfully!")
368
+
369
+
370
+ if __name__ == "__main__":
371
+ main()
@@ -0,0 +1 @@
1
+ __version__ = "0.5.2"