Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"name": "indigo",
"source": "./",
"description": "Indigo home automation development toolkit \u2014 plugin development, API integration, and control page building",
"version": "1.9.1",
"version": "1.9.2",
"repository": "https://github.com/simons-plugins/indigo-claude-plugin",
"license": "MIT",
"keywords": [
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "indigo",
"version": "1.9.1",
"version": "1.9.2",
"description": "Indigo home automation development toolkit \u2014 plugin development, API integration, and control page building",
"repository": "https://github.com/simons-plugins/indigo-claude-plugin"
}
30 changes: 30 additions & 0 deletions docs/plugin-dev/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Canonical CI workflows for Indigo plugins

Drop-in GitHub Actions workflows for any Indigo plugin in the workspace. They auto-detect the plugin bundle (`*.indigoPlugin`) so the same files work in every repo without edits.

## Files

- [`version-check.yml`](version-check.yml) — runs on PR. Extracts `PluginVersion` from `Info.plist` and fails the check if the resulting tag (`v$VERSION` or bare `$VERSION`) already exists. Enforces the workspace rule that every PR bumps the version.
- [`create-release.yml`](create-release.yml) — runs on push to `main`/`master`. If a tag for the current `PluginVersion` doesn't yet exist, it zips the plugin bundle (excluding `.pyc`, `__pycache__`, IDE files) and creates a GitHub release tagged `v$VERSION` with auto-generated release notes and the zip attached.

## Conventions

- **Tag prefix**: `v$VERSION` (e.g. `v2026.0.3`). The version-check is conservative and rejects either prefixed or bare tags clashing with the new version.
- **Plugin bundle detection**: `find . -maxdepth 1 -iname "*.indigoPlugin" -type d`. The bundle must live at the repo root. Case-insensitive (`-iname`) so legacy bundles like `HeatmiserNeo.IndigoPlugin` are matched. The detected bundle name is used verbatim throughout (no suffix-stripping with `basename`), so the asset zip preserves the exact directory case (`HeatmiserNeo.IndigoPlugin.zip`, `Domio.indigoPlugin.zip`).
- **Action versions**: `actions/checkout@v4`, `softprops/action-gh-release@v2`. Both run on Node 20.

## Usage

Copy both YAML files to `.github/workflows/` in the target repo. No edits required — the workflows discover the plugin name at runtime.

```bash
mkdir -p .github/workflows
cp /path/to/indigo-claude-plugin/docs/plugin-dev/workflows/version-check.yml .github/workflows/
cp /path/to/indigo-claude-plugin/docs/plugin-dev/workflows/create-release.yml .github/workflows/
```

Bump `PluginVersion` in `*.indigoPlugin/Contents/Info.plist`, open a PR. CI will gate the merge on a fresh version; merge to `main` triggers the release.

## Coexistence with other CI

These workflows do not interact with linting/test workflows. Repos with `tests.yml`, `test.yml`, `lint.yml`, etc. can keep them — they run as independent jobs.
81 changes: 81 additions & 0 deletions docs/plugin-dev/workflows/create-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Create Release

on:
push:
branches:
- main
- master

jobs:
create-release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Determine plugin bundle
id: get_plugin
run: |
PLUGIN_BUNDLE_PATH=$(find . -maxdepth 1 -iname "*.indigoPlugin" -type d | head -1)
if [ -z "$PLUGIN_BUNDLE_PATH" ]; then
echo "Error: No .indigoPlugin directory found in repository root." >&2
exit 1
fi
PLUGIN_BUNDLE=$(basename "$PLUGIN_BUNDLE_PATH")
echo "plugin_bundle=$PLUGIN_BUNDLE" >> $GITHUB_OUTPUT
echo "Detected plugin bundle: $PLUGIN_BUNDLE"

- name: Extract version from Info.plist
id: get_version
run: |
PLUGIN_BUNDLE="${{ steps.get_plugin.outputs.plugin_bundle }}"
VERSION=$(grep -A1 '<key>PluginVersion</key>' "${PLUGIN_BUNDLE}/Contents/Info.plist" | grep '<string>' | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
if [ -z "$VERSION" ]; then
echo "Error: Could not extract PluginVersion from Info.plist." >&2
exit 1
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Extracted version: $VERSION"

- name: Check if release already exists
id: check_release
run: |
VERSION="${{ steps.get_version.outputs.version }}"
if git rev-parse "v$VERSION" >/dev/null 2>&1; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "Release v$VERSION already exists, skipping."
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "Release v$VERSION does not exist, will create."
fi

- name: Create plugin bundle zip
if: steps.check_release.outputs.exists == 'false'
run: |
PLUGIN_BUNDLE="${{ steps.get_plugin.outputs.plugin_bundle }}"
zip -r "${PLUGIN_BUNDLE}.zip" "${PLUGIN_BUNDLE}" \
-x "*.pyc" \
-x "*/__pycache__" \
-x "*/__pycache__/*" \
-x "*.sublime-project" \
-x "*.sublime-workspace" \
-x "*/.idea" \
-x "*/.idea/*" \
-x "*.bbproject" \
-x "*.bbproject/*"
echo "Created ${PLUGIN_BUNDLE}.zip"

- name: Create GitHub Release
if: steps.check_release.outputs.exists == 'false'
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.get_version.outputs.version }}
name: Release v${{ steps.get_version.outputs.version }}
generate_release_notes: true
draft: false
prerelease: false
files: ${{ steps.get_plugin.outputs.plugin_bundle }}.zip
53 changes: 53 additions & 0 deletions docs/plugin-dev/workflows/version-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Version Check

on:
pull_request:
branches:
- main
- master

jobs:
check-version:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Determine plugin bundle
id: get_plugin
run: |
PLUGIN_BUNDLE_PATH=$(find . -maxdepth 1 -iname "*.indigoPlugin" -type d | head -1)
if [ -z "$PLUGIN_BUNDLE_PATH" ]; then
echo "Error: No .indigoPlugin directory found in repository root." >&2
exit 1
fi
PLUGIN_BUNDLE=$(basename "$PLUGIN_BUNDLE_PATH")
echo "plugin_bundle=$PLUGIN_BUNDLE" >> $GITHUB_OUTPUT
echo "Detected plugin bundle: $PLUGIN_BUNDLE"

- name: Extract version from Info.plist
id: get_version
run: |
PLUGIN_BUNDLE="${{ steps.get_plugin.outputs.plugin_bundle }}"
VERSION=$(grep -A1 '<key>PluginVersion</key>' "${PLUGIN_BUNDLE}/Contents/Info.plist" | grep '<string>' | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
if [ -z "$VERSION" ]; then
echo "Error: Could not extract PluginVersion from Info.plist." >&2
exit 1
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Extracted version: $VERSION"

- name: Check if tag already exists
run: |
VERSION="${{ steps.get_version.outputs.version }}"
if git rev-parse "v$VERSION" >/dev/null 2>&1; then
echo "::error::Version v$VERSION already exists as a git tag. Please update the PluginVersion in Info.plist."
exit 1
fi
if git rev-parse "$VERSION" >/dev/null 2>&1; then
echo "::error::Version $VERSION already exists as a git tag. Please update the PluginVersion in Info.plist."
exit 1
fi
echo "✓ Version $VERSION is new and can be released."
Loading