Skip to content

Commit 18967b4

Browse files
rrrutledgeclaude
andauthored
ci: publish workflows to n8n Cloud when they merge to main (#2)
* ci: publish workflows to n8n Cloud when they merge to main Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NHWk8qLHcjgqwXLhtgDhii * docs: drop manual republish and local-script instructions Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NHWk8qLHcjgqwXLhtgDhii --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
1 parent dc9fc14 commit 18967b4

3 files changed

Lines changed: 83 additions & 8 deletions

File tree

‎.github/workflows/publish-n8n.yml‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Publish workflows to n8n Cloud
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- "nodes/**/*.json"
8+
workflow_dispatch:
9+
inputs:
10+
file:
11+
description: "Workflow file to publish (blank publishes every workflow under nodes/)"
12+
required: false
13+
default: ""
14+
15+
permissions:
16+
contents: read
17+
18+
concurrency:
19+
group: publish-n8n
20+
cancel-in-progress: false
21+
22+
jobs:
23+
publish:
24+
runs-on: ubuntu-latest
25+
env:
26+
N8N_API_KEY: ${{ secrets.N8N_API_KEY }}
27+
BEFORE_SHA: ${{ github.event.before }}
28+
AFTER_SHA: ${{ github.sha }}
29+
INPUT_FILE: ${{ inputs.file }}
30+
steps:
31+
- uses: actions/checkout@v4
32+
with:
33+
fetch-depth: 0
34+
35+
- name: Collect workflow files
36+
run: |
37+
set -euo pipefail
38+
git config core.quotepath off
39+
if [ "${{ github.event_name }}" == "push" ] && [ "$BEFORE_SHA" != "0000000000000000000000000000000000000000" ]; then
40+
git diff -z --name-only --diff-filter=AM "$BEFORE_SHA" "$AFTER_SHA" -- 'nodes/*.json' > "$RUNNER_TEMP/files.list"
41+
elif [ -n "$INPUT_FILE" ]; then
42+
printf '%s\0' "$INPUT_FILE" > "$RUNNER_TEMP/files.list"
43+
else
44+
git ls-files -z -- 'nodes/*.json' > "$RUNNER_TEMP/files.list"
45+
fi
46+
echo "Workflows to publish: $(tr -cd '\0' < "$RUNNER_TEMP/files.list" | wc -c)"
47+
48+
- name: Publish
49+
run: |
50+
set -euo pipefail
51+
failed=0
52+
while IFS= read -r -d '' file; do
53+
echo "::group::$file"
54+
if ! bash scripts/update-workflow.sh "$file"; then
55+
failed=1
56+
fi
57+
echo "::endgroup::"
58+
done < "$RUNNER_TEMP/files.list"
59+
exit "$failed"

‎USAGE.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@
77
2. To run a workflow with Google Drive, set up OAuth2 credentials in Google Cloud Console, [here](https://console.cloud.google.com/apis/credentials).
88
4. Ask in the [#ispo-working-group](#ispo-working-group) for help with this repository.
99

10+
## Publishing workflows to n8n Cloud
11+
12+
Merging a change to a workflow JSON under `nodes/` into `main` publishes it to <https://innersourcecommons.app.n8n.cloud/> automatically, through the `Publish workflows to n8n Cloud` GitHub Action.
13+
The Action publishes only the workflow files that changed in the push.
14+
Each file is matched to its workflow by the `id` field in the JSON.
15+
Publishing replaces the workflow's name, nodes, connections, settings, and static data, and leaves its active or inactive state as it is.
16+
17+
The Action reads the API key from the `N8N_API_KEY` repository secret.
18+
1019
## Credential errors (e.g. “does not exist for type …”)
1120

1221
n8n stores credentials by **ID** on the server. If you see `Credential with ID "…" does not exist for type "googleDriveOAuth2Api"` on a node such as **Get All Folders**:

‎scripts/update-workflow.sh‎

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
#!/bin/bash
22

3-
# NOTE: This doesn't work with the $20/month starter plan. (no API access)
4-
# It does, however, work well with a local instance.
5-
# https://innersourcecommons.app.n8n.cloud/
3+
# Pushes one workflow JSON file to https://innersourcecommons.app.n8n.cloud/
4+
# using the API key in $N8N_API_KEY. CI runs this for each workflow merged to main.
5+
# Exits non-zero unless the API answers 200.
66

77
# Check if a file was provided
88
if [ -z "$1" ]; then
99
echo "Usage: ./update-workflow.sh <path-to-workflow.json>"
1010
exit 1
1111
fi
1212

13+
if [ -z "$N8N_API_KEY" ]; then
14+
echo "Error: N8N_API_KEY is not set."
15+
exit 1
16+
fi
17+
1318
WORKFLOW_FILE="$1"
1419
BASE_URL="https://innersourcecommons.app.n8n.cloud/api/v1"
1520

@@ -31,20 +36,22 @@ jq '{name, nodes, connections, settings, staticData} | with_entries(select(.valu
3136
# Update the workflow
3237
# The API expects the workflow JSON object in the body.
3338
# We assume the file contains the full workflow object.
34-
response=$(curl -s -X PUT "$BASE_URL/workflows/$WORKFLOW_ID" \
39+
RESPONSE_FILE=$(mktemp)
40+
status=$(curl -s -o "$RESPONSE_FILE" -w "%{http_code}" -X PUT "$BASE_URL/workflows/$WORKFLOW_ID" \
3541
-H "X-N8N-API-KEY: $N8N_API_KEY" \
3642
-H "Content-Type: application/json" \
3743
-d @"$CLEAN_JSON_FILE")
3844

3945
# Clean up
4046
rm "$CLEAN_JSON_FILE"
4147

42-
# Check if update was successful (look for id in response)
43-
if echo "$response" | grep -q "\"id\":\"$WORKFLOW_ID\""; then
48+
if [ "$status" == "200" ]; then
4449
echo "Successfully updated workflow."
50+
rm "$RESPONSE_FILE"
4551
else
46-
echo "Failed to update workflow. Response:"
47-
echo "$response"
52+
echo "Failed to update workflow (HTTP $status). Response:"
53+
cat "$RESPONSE_FILE"
54+
rm "$RESPONSE_FILE"
4855
exit 1
4956
fi
5057

0 commit comments

Comments
 (0)