Skip to content

Commit 4775aa9

Browse files
minsoo-webclaude
andcommitted
feat: initial chromaport - VS Code/Cursor theme migrator for Superset and Warp
Rust CLI tool that reads VS Code/Cursor theme extensions and converts them to Superset (app-state.json) and Warp (~/.warp/themes/*.yaml) formats. - Interactive multi-select UI for theme and target selection - JSONC parsing with comment stripping and include inheritance - Atomic file writes with path traversal prevention - cargo-dist + Homebrew tap release pipeline - CI quality gates: fmt, clippy, test, typos, ls-lint - Bail on Superset write when app is running (prevents overwrite) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
0 parents  commit 4775aa9

24 files changed

Lines changed: 3632 additions & 0 deletions

.cargo/config.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[alias]
2+
ck = "check --all-targets --all-features"
3+
fmt-check = "fmt --all -- --check"
4+
lint = "clippy --all-targets --all-features -- -D warnings"

.github/workflows/ci.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
workflow_dispatch:
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
12+
cancel-in-progress: true
13+
14+
jobs:
15+
fmt-check:
16+
name: Rust Format Check
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v4
20+
- uses: dtolnay/rust-toolchain@stable
21+
with:
22+
components: rustfmt
23+
- uses: Swatinem/rust-cache@v2
24+
- run: cargo fmt-check
25+
26+
clippy:
27+
name: Rust Lint (Clippy)
28+
runs-on: ubuntu-latest
29+
steps:
30+
- uses: actions/checkout@v4
31+
- uses: dtolnay/rust-toolchain@stable
32+
with:
33+
components: clippy
34+
- uses: Swatinem/rust-cache@v2
35+
- run: cargo lint
36+
37+
test:
38+
name: Rust Test
39+
runs-on: ubuntu-latest
40+
steps:
41+
- uses: actions/checkout@v4
42+
- uses: dtolnay/rust-toolchain@stable
43+
- uses: Swatinem/rust-cache@v2
44+
- run: cargo test
45+
46+
typos:
47+
name: Typo Check
48+
runs-on: ubuntu-latest
49+
steps:
50+
- uses: actions/checkout@v4
51+
- uses: crate-ci/typos@v1.36.2
52+
53+
ls-lint:
54+
name: Naming Lint
55+
runs-on: ubuntu-latest
56+
steps:
57+
- uses: actions/checkout@v4
58+
- uses: actions/setup-node@v4
59+
with:
60+
node-version: 22
61+
- run: npm install --global @ls-lint/ls-lint
62+
- run: ls-lint -config .ls-lint.json

.github/workflows/release.yml

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
# Autogenerated by dist: https://axodotdev.github.io/cargo-dist
2+
name: Release
3+
4+
permissions:
5+
contents: write
6+
7+
on:
8+
pull_request:
9+
push:
10+
tags:
11+
- '**[0-9]+.[0-9]+.[0-9]+*'
12+
13+
jobs:
14+
plan:
15+
runs-on: ubuntu-22.04
16+
outputs:
17+
val: ${{ steps.plan.outputs.manifest }}
18+
tag: ${{ !github.event.pull_request && github.ref_name || '' }}
19+
tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }}
20+
publishing: ${{ !github.event.pull_request }}
21+
env:
22+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
23+
steps:
24+
- uses: actions/checkout@v6
25+
with:
26+
persist-credentials: false
27+
submodules: recursive
28+
- name: Install dist
29+
shell: bash
30+
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.31.0/cargo-dist-installer.sh | sh"
31+
- name: Cache dist
32+
uses: actions/upload-artifact@v6
33+
with:
34+
name: cargo-dist-cache
35+
path: ~/.cargo/bin/dist
36+
- id: plan
37+
run: |
38+
dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json
39+
echo "dist ran successfully"
40+
cat plan-dist-manifest.json
41+
echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT"
42+
- name: Upload dist-manifest.json
43+
uses: actions/upload-artifact@v6
44+
with:
45+
name: artifacts-plan-dist-manifest
46+
path: plan-dist-manifest.json
47+
48+
build-local-artifacts:
49+
name: build-local-artifacts (${{ join(matrix.targets, ', ') }})
50+
needs: plan
51+
if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }}
52+
strategy:
53+
fail-fast: false
54+
matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }}
55+
runs-on: ${{ matrix.runner }}
56+
container: ${{ matrix.container && matrix.container.image || null }}
57+
env:
58+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
59+
BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json
60+
steps:
61+
- name: enable windows longpaths
62+
run: git config --global core.longpaths true
63+
- uses: actions/checkout@v6
64+
with:
65+
persist-credentials: false
66+
submodules: recursive
67+
- name: Install Rust non-interactively if not already installed
68+
if: ${{ matrix.container }}
69+
run: |
70+
if ! command -v cargo > /dev/null 2>&1; then
71+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
72+
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
73+
fi
74+
- name: Install dist
75+
run: ${{ matrix.install_dist.run }}
76+
- name: Fetch local artifacts
77+
uses: actions/download-artifact@v7
78+
with:
79+
pattern: artifacts-*
80+
path: target/distrib/
81+
merge-multiple: true
82+
- name: Install dependencies
83+
run: ${{ matrix.packages_install }}
84+
- name: Build artifacts
85+
run: |
86+
dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json
87+
echo "dist ran successfully"
88+
- id: cargo-dist
89+
shell: bash
90+
run: |
91+
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
92+
dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT"
93+
echo "EOF" >> "$GITHUB_OUTPUT"
94+
cp dist-manifest.json "$BUILD_MANIFEST_NAME"
95+
- name: Upload artifacts
96+
uses: actions/upload-artifact@v6
97+
with:
98+
name: artifacts-build-local-${{ join(matrix.targets, '_') }}
99+
path: |
100+
${{ steps.cargo-dist.outputs.paths }}
101+
${{ env.BUILD_MANIFEST_NAME }}
102+
103+
build-global-artifacts:
104+
needs: [plan, build-local-artifacts]
105+
runs-on: ubuntu-22.04
106+
env:
107+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
108+
BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
109+
steps:
110+
- uses: actions/checkout@v6
111+
with:
112+
persist-credentials: false
113+
submodules: recursive
114+
- name: Install cached dist
115+
uses: actions/download-artifact@v7
116+
with:
117+
name: cargo-dist-cache
118+
path: ~/.cargo/bin/
119+
- run: chmod +x ~/.cargo/bin/dist
120+
- name: Fetch local artifacts
121+
uses: actions/download-artifact@v7
122+
with:
123+
pattern: artifacts-*
124+
path: target/distrib/
125+
merge-multiple: true
126+
- id: cargo-dist
127+
shell: bash
128+
run: |
129+
dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json
130+
echo "dist ran successfully"
131+
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
132+
jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT"
133+
echo "EOF" >> "$GITHUB_OUTPUT"
134+
cp dist-manifest.json "$BUILD_MANIFEST_NAME"
135+
- name: Upload artifacts
136+
uses: actions/upload-artifact@v6
137+
with:
138+
name: artifacts-build-global
139+
path: |
140+
${{ steps.cargo-dist.outputs.paths }}
141+
${{ env.BUILD_MANIFEST_NAME }}
142+
143+
host:
144+
needs: [plan, build-local-artifacts, build-global-artifacts]
145+
if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
146+
env:
147+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
148+
runs-on: ubuntu-22.04
149+
outputs:
150+
val: ${{ steps.host.outputs.manifest }}
151+
steps:
152+
- uses: actions/checkout@v6
153+
with:
154+
persist-credentials: false
155+
submodules: recursive
156+
- name: Install cached dist
157+
uses: actions/download-artifact@v7
158+
with:
159+
name: cargo-dist-cache
160+
path: ~/.cargo/bin/
161+
- run: chmod +x ~/.cargo/bin/dist
162+
- name: Fetch artifacts
163+
uses: actions/download-artifact@v7
164+
with:
165+
pattern: artifacts-*
166+
path: target/distrib/
167+
merge-multiple: true
168+
- id: host
169+
shell: bash
170+
run: |
171+
dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json
172+
echo "artifacts uploaded and released successfully"
173+
cat dist-manifest.json
174+
echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT"
175+
- name: Upload dist-manifest.json
176+
uses: actions/upload-artifact@v6
177+
with:
178+
name: artifacts-dist-manifest
179+
path: dist-manifest.json
180+
- name: Download GitHub Artifacts
181+
uses: actions/download-artifact@v7
182+
with:
183+
pattern: artifacts-*
184+
path: artifacts
185+
merge-multiple: true
186+
- name: Cleanup
187+
run: rm -f artifacts/*-dist-manifest.json
188+
- name: Create GitHub Release
189+
env:
190+
PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}"
191+
ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}"
192+
ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}"
193+
RELEASE_COMMIT: "${{ github.sha }}"
194+
run: |
195+
echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt
196+
gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/*
197+
198+
publish-homebrew-formula:
199+
needs: [plan, host]
200+
runs-on: ubuntu-22.04
201+
env:
202+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
203+
PLAN: ${{ needs.plan.outputs.val }}
204+
GITHUB_USER: "axo bot"
205+
GITHUB_EMAIL: "admin+bot@axo.dev"
206+
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
207+
steps:
208+
- uses: actions/checkout@v6
209+
with:
210+
persist-credentials: true
211+
repository: "hamsurang/homebrew-chromaport"
212+
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
213+
- name: Fetch homebrew formulae
214+
uses: actions/download-artifact@v7
215+
with:
216+
pattern: artifacts-*
217+
path: Formula/
218+
merge-multiple: true
219+
- name: Commit formula files
220+
run: |
221+
git config --global user.name "${GITHUB_USER}"
222+
git config --global user.email "${GITHUB_EMAIL}"
223+
for release in $(echo "$PLAN" | jq --compact-output '.releases[] | select([.artifacts[] | endswith(".rb")] | any)'); do
224+
filename=$(echo "$release" | jq '.artifacts[] | select(endswith(".rb"))' --raw-output)
225+
name=$(echo "$filename" | sed "s/\.rb$//")
226+
version=$(echo "$release" | jq .app_version --raw-output)
227+
export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH"
228+
brew update
229+
brew style --except-cops FormulaAudit/Homepage,FormulaAudit/Desc,FormulaAuditStrict --fix "Formula/${filename}" || true
230+
git add "Formula/${filename}"
231+
git commit -m "${name} ${version}"
232+
done
233+
git push
234+
235+
announce:
236+
needs: [plan, host, publish-homebrew-formula]
237+
if: ${{ always() && needs.host.result == 'success' && (needs.publish-homebrew-formula.result == 'skipped' || needs.publish-homebrew-formula.result == 'success') }}
238+
runs-on: ubuntu-22.04
239+
env:
240+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
241+
steps:
242+
- uses: actions/checkout@v6
243+
with:
244+
persist-credentials: false
245+
submodules: recursive

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

.ls-lint.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"file": {
3+
"*.rs": "snake_case"
4+
},
5+
"ignore": [
6+
".git/**",
7+
".github/**",
8+
".vscode/**",
9+
"target/**"
10+
]
11+
}

0 commit comments

Comments
 (0)