55 tags : ["plugin-*-v*"]
66 workflow_dispatch :
77 inputs :
8- tag :
9- description : " Plugin tag to build (e.g., plugin-oracle-v1.0.1)"
8+ tags :
9+ description : " Plugin tags, comma-separated (e.g., plugin-oracle-v1.0.1,plugin-sqlite -v1.0.1)"
1010 required : true
1111 type : string
1212
2020 build-plugin :
2121 name : Build Plugin
2222 runs-on : self-hosted
23- timeout-minutes : 30
23+ timeout-minutes : 60
2424
2525 steps :
26- - name : Extract plugin info from tag
27- id : plugin-info
28- run : |
29- TAG="${{ inputs.tag || github.ref_name }}"
30- # Tag format: plugin-<name>-v<version>
31- # e.g., plugin-oracle-v1.0.0 -> OracleDriverPlugin
32- PLUGIN_NAME=$(echo "$TAG" | sed -E 's/^plugin-([a-z]+)-v.*$/\1/')
33- VERSION=$(echo "$TAG" | sed -E 's/^plugin-[a-z]+-v(.*)$/\1/')
34-
35- # Map short name to Xcode target and registry metadata
36- case "$PLUGIN_NAME" in
37- oracle)
38- TARGET="OracleDriver"
39- BUNDLE_ID="com.TablePro.OracleDriver"
40- DISPLAY_NAME="Oracle Driver"
41- SUMMARY="Oracle Database 12c+ driver via OracleNIO"
42- DB_TYPE_IDS='["Oracle"]'
43- ICON="server.rack"
44- BUNDLE_NAME="OracleDriver"
45- HOMEPAGE="https://tablepro.app/databases/oracle"
46- ;;
47- clickhouse)
48- TARGET="ClickHouseDriver"
49- BUNDLE_ID="com.TablePro.ClickHouseDriver"
50- DISPLAY_NAME="ClickHouse Driver"
51- SUMMARY="ClickHouse OLAP database driver via HTTP interface"
52- DB_TYPE_IDS='["ClickHouse"]'
53- ICON="chart.bar.xaxis"
54- BUNDLE_NAME="ClickHouseDriver"
55- HOMEPAGE="https://tablepro.app/databases/clickhouse"
56- ;;
57- sqlite)
58- TARGET="SQLiteDriver"
59- BUNDLE_ID="com.TablePro.SQLiteDriver"
60- DISPLAY_NAME="SQLite Driver"
61- SUMMARY="SQLite embedded database driver"
62- DB_TYPE_IDS='["SQLite"]'
63- ICON="internaldrive"
64- BUNDLE_NAME="SQLiteDriver"
65- HOMEPAGE="https://tablepro.app"
66- ;;
67- duckdb)
68- TARGET="DuckDBDriver"
69- BUNDLE_ID="com.TablePro.DuckDBDriver"
70- DISPLAY_NAME="DuckDB Driver"
71- SUMMARY="DuckDB analytical database driver"
72- DB_TYPE_IDS='["DuckDB"]'
73- ICON="bird"
74- BUNDLE_NAME="DuckDBDriver"
75- HOMEPAGE="https://tablepro.app"
76- ;;
77- *) echo "Unknown plugin: $PLUGIN_NAME"; exit 1 ;;
78- esac
79-
80- echo "target=$TARGET" >> "$GITHUB_OUTPUT"
81- echo "version=$VERSION" >> "$GITHUB_OUTPUT"
82- echo "plugin_name=$PLUGIN_NAME" >> "$GITHUB_OUTPUT"
83- echo "bundle_id=$BUNDLE_ID" >> "$GITHUB_OUTPUT"
84- echo "display_name=$DISPLAY_NAME" >> "$GITHUB_OUTPUT"
85- echo "summary=$SUMMARY" >> "$GITHUB_OUTPUT"
86- echo "db_type_ids=$DB_TYPE_IDS" >> "$GITHUB_OUTPUT"
87- echo "icon=$ICON" >> "$GITHUB_OUTPUT"
88- echo "bundle_name=$BUNDLE_NAME" >> "$GITHUB_OUTPUT"
89- echo "homepage=$HOMEPAGE" >> "$GITHUB_OUTPUT"
90- echo "Building $TARGET v$VERSION"
91-
9226 - name : Install Git LFS
9327 run : brew list git-lfs &>/dev/null || brew install git-lfs; git lfs install
9428
@@ -100,142 +34,175 @@ jobs:
10034 - name : Pull LFS files
10135 run : git lfs pull
10236
103- - name : Build plugin (ARM64)
104- run : ./scripts/build-plugin.sh "${{ steps.plugin-info.outputs.target }}" arm64
105-
106- - name : Build plugin (x86_64)
107- run : ./scripts/build-plugin.sh "${{ steps.plugin-info.outputs.target }}" x86_64
108-
109- - name : Capture SHA-256 hashes
110- # Hashes are captured before notarize intentionally: notarytool does not
111- # modify the ZIP on disk, and stapling applies to app bundles, not ZIPs.
112- id : sha256
113- run : |
114- BUNDLE_NAME="${{ steps.plugin-info.outputs.bundle_name }}"
115- ARM64_SHA=$(cat "build/Plugins/${BUNDLE_NAME}-arm64.zip.sha256")
116- X86_SHA=$(cat "build/Plugins/${BUNDLE_NAME}-x86_64.zip.sha256")
117- echo "arm64=$ARM64_SHA" >> "$GITHUB_OUTPUT"
118- echo "x86_64=$X86_SHA" >> "$GITHUB_OUTPUT"
119-
120- - name : Notarize
121- if : vars.NOTARIZE_PLUGINS == 'true'
122- run : |
123- for zip in build/Plugins/*.zip; do
124- xcrun notarytool submit "$zip" \
125- --apple-id "$APPLE_ID" \
126- --team-id "D7HJ5TFYCU" \
127- --keychain-profile "notarytool-profile" \
128- --wait
129- done
130-
131- - name : Create GitHub Release
132- uses : softprops/action-gh-release@v2
133- with :
134- name : " ${{ steps.plugin-info.outputs.display_name }} v${{ steps.plugin-info.outputs.version }}"
135- body : |
136- ## ${{ steps.plugin-info.outputs.display_name }} v${{ steps.plugin-info.outputs.version }}
137-
138- Plugin release for TablePro.
139-
140- ### Installation
141- TablePro will prompt you to install this plugin automatically when you select the database type. You can also install manually via **Settings > Plugins > Browse**.
142-
143- ### SHA-256
144- - ARM64: `${{ steps.sha256.outputs.arm64 }}`
145- - x86_64: `${{ steps.sha256.outputs.x86_64 }}`
146- files : build/Plugins/*.zip
147- draft : false
148- prerelease : false
149-
150- - name : Update plugin registry
37+ - name : Build and release plugins
15138 env :
15239 REGISTRY_DEPLOY_KEY : ${{ secrets.REGISTRY_DEPLOY_KEY }}
40+ GH_TOKEN : ${{ github.token }}
15341 run : |
154- TAG="${{ inputs.tag || github.ref_name }}"
155-
156- ARM64_URL="https://github.com/${{ github.repository }}/releases/download/${TAG}/${{ steps.plugin-info.outputs.bundle_name }}-arm64.zip"
157- X86_64_URL="https://github.com/${{ github.repository }}/releases/download/${TAG}/${{ steps.plugin-info.outputs.bundle_name }}-x86_64.zip"
158-
159- # Get current app version as minAppVersion
42+ # Build tag list: from input (comma-separated) or from push event (single tag)
43+ if [ -n "${{ inputs.tags }}" ]; then
44+ IFS=',' read -ra TAGS <<< "${{ inputs.tags }}"
45+ else
46+ TAGS=("${{ github.ref_name }}")
47+ fi
48+
49+ # Get current app version for minAppVersion
16050 MIN_APP_VERSION=$(sed -n 's/.*MARKETING_VERSION = \(.*\);/\1/p' \
16151 TablePro.xcodeproj/project.pbxproj | head -1 | tr -d ' ')
16252
163- # Clone the registry repo
164- WORK=$(mktemp -d)
165- eval "$(ssh-agent -s)"
166- echo "$REGISTRY_DEPLOY_KEY" | ssh-add -
167- git clone git@github.com:datlechin/tablepro-plugins.git "$WORK/registry"
168- cd "$WORK/registry"
169-
170- # Update plugins.json via Python
171- python3 - \
172- "${{ steps.plugin-info.outputs.bundle_id }}" \
173- "${{ steps.plugin-info.outputs.display_name }}" \
174- "${{ steps.plugin-info.outputs.version }}" \
175- "${{ steps.plugin-info.outputs.summary }}" \
176- '${{ steps.plugin-info.outputs.db_type_ids }}' \
177- "$ARM64_URL" \
178- "${{ steps.sha256.outputs.arm64 }}" \
179- "$X86_64_URL" \
180- "${{ steps.sha256.outputs.x86_64 }}" \
181- "$MIN_APP_VERSION" \
182- "${{ steps.plugin-info.outputs.icon }}" \
183- "${{ steps.plugin-info.outputs.homepage }}" \
184- <<'PYTHON_SCRIPT'
185- import json, sys
186-
187- bundle_id = sys.argv[1]
188- name = sys.argv[2]
189- version = sys.argv[3]
190- summary = sys.argv[4]
191- db_type_ids = json.loads(sys.argv[5])
192- arm64_url = sys.argv[6]
193- arm64_sha = sys.argv[7]
194- x86_64_url = sys.argv[8]
195- x86_64_sha = sys.argv[9]
196- min_app_version = sys.argv[10]
197- icon = sys.argv[11]
198- homepage = sys.argv[12]
199-
200- with open("plugins.json", "r") as f:
201- manifest = json.load(f)
202-
203- entry = {
204- "id": bundle_id,
205- "name": name,
206- "version": version,
207- "summary": summary,
208- "author": {"name": "TablePro", "url": "https://tablepro.app"},
209- "homepage": homepage,
210- "category": "database-driver",
211- "databaseTypeIds": db_type_ids,
212- "downloadURL": arm64_url,
213- "sha256": arm64_sha,
214- "binaries": [
215- {"architecture": "arm64", "downloadURL": arm64_url, "sha256": arm64_sha},
216- {"architecture": "x86_64", "downloadURL": x86_64_url, "sha256": x86_64_sha}
217- ],
218- "minAppVersion": min_app_version,
219- "minPluginKitVersion": 1,
220- "iconName": icon,
221- "isVerified": True
53+ resolve_plugin_info() {
54+ local plugin_name=$1
55+ case "$plugin_name" in
56+ oracle)
57+ TARGET="OracleDriver"; BUNDLE_ID="com.TablePro.OracleDriver"
58+ DISPLAY_NAME="Oracle Driver"; SUMMARY="Oracle Database 12c+ driver via OracleNIO"
59+ DB_TYPE_IDS='["Oracle"]'; ICON="server.rack"; BUNDLE_NAME="OracleDriver"
60+ HOMEPAGE="https://tablepro.app/databases/oracle" ;;
61+ clickhouse)
62+ TARGET="ClickHouseDriver"; BUNDLE_ID="com.TablePro.ClickHouseDriver"
63+ DISPLAY_NAME="ClickHouse Driver"; SUMMARY="ClickHouse OLAP database driver via HTTP interface"
64+ DB_TYPE_IDS='["ClickHouse"]'; ICON="chart.bar.xaxis"; BUNDLE_NAME="ClickHouseDriver"
65+ HOMEPAGE="https://tablepro.app/databases/clickhouse" ;;
66+ sqlite)
67+ TARGET="SQLiteDriver"; BUNDLE_ID="com.TablePro.SQLiteDriver"
68+ DISPLAY_NAME="SQLite Driver"; SUMMARY="SQLite embedded database driver"
69+ DB_TYPE_IDS='["SQLite"]'; ICON="internaldrive"; BUNDLE_NAME="SQLiteDriver"
70+ HOMEPAGE="https://tablepro.app" ;;
71+ duckdb)
72+ TARGET="DuckDBDriver"; BUNDLE_ID="com.TablePro.DuckDBDriver"
73+ DISPLAY_NAME="DuckDB Driver"; SUMMARY="DuckDB analytical database driver"
74+ DB_TYPE_IDS='["DuckDB"]'; ICON="bird"; BUNDLE_NAME="DuckDBDriver"
75+ HOMEPAGE="https://tablepro.app" ;;
76+ *) echo "Unknown plugin: $plugin_name"; return 1 ;;
77+ esac
22278 }
22379
224- manifest["plugins"] = [p for p in manifest["plugins"] if p["id"] != bundle_id]
225- manifest["plugins"].append(entry)
226-
227- with open("plugins.json", "w") as f:
228- json.dump(manifest, f, indent=2)
229- f.write("\n")
80+ for TAG in "${TAGS[@]}"; do
81+ TAG=$(echo "$TAG" | xargs) # trim whitespace
82+ echo ""
83+ echo "========================================"
84+ echo "Processing: $TAG"
85+ echo "========================================"
86+
87+ PLUGIN_NAME=$(echo "$TAG" | sed -E 's/^plugin-([a-z]+)-v.*$/\1/')
88+ VERSION=$(echo "$TAG" | sed -E 's/^plugin-[a-z]+-v(.*)$/\1/')
89+
90+ resolve_plugin_info "$PLUGIN_NAME" || continue
91+
92+ echo "Building $TARGET v$VERSION"
93+
94+ # Build both architectures
95+ ./scripts/build-plugin.sh "$TARGET" arm64
96+ ./scripts/build-plugin.sh "$TARGET" x86_64
97+
98+ # Capture SHA-256
99+ ARM64_SHA=$(cat "build/Plugins/${BUNDLE_NAME}-arm64.zip.sha256")
100+ X86_SHA=$(cat "build/Plugins/${BUNDLE_NAME}-x86_64.zip.sha256")
101+
102+ # Notarize if enabled
103+ if [ "${NOTARIZE_PLUGINS:-}" = "true" ]; then
104+ for zip in build/Plugins/${BUNDLE_NAME}-*.zip; do
105+ xcrun notarytool submit "$zip" \
106+ --apple-id "$APPLE_ID" \
107+ --team-id "D7HJ5TFYCU" \
108+ --keychain-profile "notarytool-profile" \
109+ --wait
110+ done
111+ fi
112+
113+ # Create GitHub Release
114+ RELEASE_BODY="## $DISPLAY_NAME v$VERSION
115+
116+ Plugin release for TablePro.
117+
118+ ### Installation
119+ TablePro will prompt you to install this plugin automatically when you select the database type. You can also install manually via **Settings > Plugins > Browse**.
120+
121+ ### SHA-256
122+ - ARM64: \`$ARM64_SHA\`
123+ - x86_64: \`$X86_SHA\`"
124+
125+ # Delete existing release if any, then create
126+ gh release delete "$TAG" --yes 2>/dev/null || true
127+ gh release create "$TAG" \
128+ --title "$DISPLAY_NAME v$VERSION" \
129+ --notes "$RELEASE_BODY" \
130+ build/Plugins/${BUNDLE_NAME}-arm64.zip \
131+ build/Plugins/${BUNDLE_NAME}-x86_64.zip
132+
133+ # Update plugin registry
134+ if [ -n "${REGISTRY_DEPLOY_KEY:-}" ]; then
135+ ARM64_URL="https://github.com/${{ github.repository }}/releases/download/${TAG}/${BUNDLE_NAME}-arm64.zip"
136+ X86_64_URL="https://github.com/${{ github.repository }}/releases/download/${TAG}/${BUNDLE_NAME}-x86_64.zip"
137+
138+ WORK=$(mktemp -d)
139+ eval "$(ssh-agent -s)"
140+ echo "$REGISTRY_DEPLOY_KEY" | ssh-add -
141+
142+ git clone git@github.com:datlechin/tablepro-plugins.git "$WORK/registry"
143+ cd "$WORK/registry"
144+ git pull --rebase origin main
145+
146+ python3 - \
147+ "$BUNDLE_ID" "$DISPLAY_NAME" "$VERSION" "$SUMMARY" \
148+ "$DB_TYPE_IDS" "$ARM64_URL" "$ARM64_SHA" \
149+ "$X86_64_URL" "$X86_SHA" "$MIN_APP_VERSION" \
150+ "$ICON" "$HOMEPAGE" \
151+ <<'PYTHON_SCRIPT'
152+ import json, sys
153+
154+ bundle_id, name, version, summary = sys.argv[1:5]
155+ db_type_ids = json.loads(sys.argv[5])
156+ arm64_url, arm64_sha = sys.argv[6], sys.argv[7]
157+ x86_64_url, x86_64_sha = sys.argv[8], sys.argv[9]
158+ min_app_version, icon, homepage = sys.argv[10], sys.argv[11], sys.argv[12]
159+
160+ with open("plugins.json", "r") as f:
161+ manifest = json.load(f)
162+
163+ entry = {
164+ "id": bundle_id, "name": name, "version": version,
165+ "summary": summary,
166+ "author": {"name": "TablePro", "url": "https://tablepro.app"},
167+ "homepage": homepage, "category": "database-driver",
168+ "databaseTypeIds": db_type_ids,
169+ "downloadURL": arm64_url, "sha256": arm64_sha,
170+ "binaries": [
171+ {"architecture": "arm64", "downloadURL": arm64_url, "sha256": arm64_sha},
172+ {"architecture": "x86_64", "downloadURL": x86_64_url, "sha256": x86_64_sha}
173+ ],
174+ "minAppVersion": min_app_version,
175+ "minPluginKitVersion": 1,
176+ "iconName": icon, "isVerified": True
177+ }
178+
179+ manifest["plugins"] = [p for p in manifest["plugins"] if p["id"] != bundle_id]
180+ manifest["plugins"].append(entry)
181+
182+ with open("plugins.json", "w") as f:
183+ json.dump(manifest, f, indent=2)
184+ f.write("\n")
230185 PYTHON_SCRIPT
231186
232- git config user.name "github-actions[bot]"
233- git config user.email "github-actions[bot]@users.noreply.github.com"
234- git add plugins.json
235- git commit -m "Update ${{ steps.plugin-info.outputs.display_name }} to v${{ steps.plugin-info.outputs.version }}"
236- git push
187+ git config user.name "github-actions[bot]"
188+ git config user.email "github-actions[bot]@users.noreply.github.com"
189+ git add plugins.json
190+ git commit -m "Update $DISPLAY_NAME to v$VERSION"
191+ git push
192+
193+ ssh-add -D
194+ eval "$(ssh-agent -k)"
195+ cd -
196+ rm -rf "$WORK"
197+ fi
198+
199+ # Clean plugin build artifacts for next iteration
200+ rm -f build/Plugins/${BUNDLE_NAME}-*.zip build/Plugins/${BUNDLE_NAME}-*.sha256
201+
202+ echo "✅ $DISPLAY_NAME v$VERSION released"
203+ done
237204
238- # Cleanup
239- ssh-add -D
240- eval "$(ssh-agent -k) "
241- rm -rf "$WORK "
205+ echo ""
206+ echo "========================================"
207+ echo "All plugins processed! "
208+ echo "======================================== "
0 commit comments