mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-06-24 23:00:29 +01:00
feat!: replace workflow_run with repository_dispatch for real-time build status updates
Replaces the workflow_run trigger mechanism with repository_dispatch events to enable real-time build status communication between build workflows and the artifact comment system. Build workflows now actively notify the comment workflow when builds start, complete, or fail, providing immediate status updates rather than polling for completed workflows. Adds real-time payload processing to display current build status and target information in PR comments, improving visibility into ongoing build processes. BREAKING CHANGE: Changes the trigger mechanism from workflow_run to repository_dispatch, requiring build workflows to explicitly send status notifications.
This commit is contained in:
110
.github/workflows/artifact-comment.yml
vendored
110
.github/workflows/artifact-comment.yml
vendored
@@ -1,56 +1,61 @@
|
|||||||
name: 📝 Artifact Comment on PR
|
name: 📝 Artifact Comment on PR
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: artifact-comment-${{ github.event.workflow_run.head_sha || github.sha }}
|
group: artifact-comment-${{ github.sha }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch: # Allow manual testing
|
workflow_dispatch: # Allow manual testing
|
||||||
pull_request: # Show in PR checks and provide status updates
|
pull_request: # Show in PR checks and provide status updates
|
||||||
types: [opened, synchronize, reopened]
|
types: [opened, synchronize, reopened]
|
||||||
workflow_run:
|
repository_dispatch: # Triggered by build workflows when they start/complete
|
||||||
workflows:
|
|
||||||
- "🤖 Android APK Build (Phone + TV)"
|
|
||||||
- "🤖 iOS IPA Build (Phone + TV)"
|
|
||||||
types:
|
types:
|
||||||
- completed
|
- build-started
|
||||||
- requested # Trigger when build starts
|
- build-completed
|
||||||
|
- build-failed
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
comment-artifacts:
|
comment-artifacts:
|
||||||
if: github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' || (github.event_name == 'workflow_run' && github.event.workflow_run.event == 'pull_request')
|
if: github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' || github.event_name == 'repository_dispatch'
|
||||||
name: 📦 Post Build Artifacts
|
name: 📦 Post Build Artifacts
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
actions: read
|
actions: read
|
||||||
|
repository-projects: read
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 🔍 Get PR and Artifacts
|
- name: 🔍 Get PR and Artifacts
|
||||||
uses: actions/github-script@v8
|
uses: actions/github-script@v8
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
// Handle workflow_run, pull_request, and manual dispatch events
|
// Handle repository_dispatch, pull_request, and manual dispatch events
|
||||||
let pr;
|
let pr;
|
||||||
|
let targetCommitSha;
|
||||||
|
|
||||||
if (context.eventName === 'workflow_run') {
|
if (context.eventName === 'repository_dispatch') {
|
||||||
// Find PR associated with this commit
|
// Triggered by build workflows - get PR info from payload
|
||||||
const { data: pullRequests } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
|
const payload = context.payload.client_payload;
|
||||||
owner: context.repo.owner,
|
console.log('Repository dispatch payload:', JSON.stringify(payload, null, 2));
|
||||||
repo: context.repo.repo,
|
|
||||||
commit_sha: github.event.workflow_run.head_sha
|
|
||||||
});
|
|
||||||
|
|
||||||
if (pullRequests.length === 0) {
|
if (!payload || !payload.pr_number) {
|
||||||
console.log('No pull request found for commit:', github.event.workflow_run.head_sha);
|
console.log('No PR information in repository_dispatch payload');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pr = pullRequests[0];
|
|
||||||
|
const { data: prData } = await github.rest.pulls.get({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
pull_number: payload.pr_number
|
||||||
|
});
|
||||||
|
pr = prData;
|
||||||
|
targetCommitSha = payload.commit_sha || pr.head.sha;
|
||||||
|
|
||||||
} else if (context.eventName === 'pull_request') {
|
} else if (context.eventName === 'pull_request') {
|
||||||
// Direct PR event
|
// Direct PR event
|
||||||
pr = context.payload.pull_request;
|
pr = context.payload.pull_request;
|
||||||
|
targetCommitSha = pr.head.sha;
|
||||||
|
|
||||||
} else if (context.eventName === 'workflow_dispatch') {
|
} else if (context.eventName === 'workflow_dispatch') {
|
||||||
// Get current PR for manual testing
|
// Get current PR for manual testing
|
||||||
@@ -61,19 +66,20 @@ jobs:
|
|||||||
pull_number: prNumber
|
pull_number: prNumber
|
||||||
});
|
});
|
||||||
pr = prData;
|
pr = prData;
|
||||||
|
targetCommitSha = pr.head.sha;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.log('Unsupported event type:', context.eventName);
|
console.log('Unsupported event type:', context.eventName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Processing PR #${pr.number} for commit ${pr.head.sha.substring(0, 7)}`);
|
console.log(`Processing PR #${pr.number} for commit ${targetCommitSha.substring(0, 7)}`);
|
||||||
|
|
||||||
// Get all recent workflow runs for this PR to collect artifacts from multiple builds
|
// Get all recent workflow runs for this PR to collect artifacts from multiple builds
|
||||||
const { data: workflowRuns } = await github.rest.actions.listWorkflowRunsForRepo({
|
const { data: workflowRuns } = await github.rest.actions.listWorkflowRunsForRepo({
|
||||||
owner: context.repo.owner,
|
owner: context.repo.owner,
|
||||||
repo: context.repo.repo,
|
repo: context.repo.repo,
|
||||||
head_sha: pr.head.sha,
|
head_sha: targetCommitSha,
|
||||||
per_page: 30
|
per_page: 30
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -151,11 +157,50 @@ jobs:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Override with real-time data from repository_dispatch if available
|
||||||
|
if (context.eventName === 'repository_dispatch') {
|
||||||
|
const payload = context.payload.client_payload;
|
||||||
|
const workflowType = payload.workflow_name.includes('Android') ? 'Android' : 'iOS';
|
||||||
|
|
||||||
|
if (buildStatuses[workflowType]) {
|
||||||
|
// Update the existing status with real-time data
|
||||||
|
buildStatuses[workflowType].status = payload.status === 'in_progress' ? 'in_progress' :
|
||||||
|
payload.status === 'success' ? 'completed' :
|
||||||
|
payload.status === 'failure' ? 'completed' :
|
||||||
|
buildStatuses[workflowType].status;
|
||||||
|
buildStatuses[workflowType].conclusion = payload.status === 'success' ? 'success' :
|
||||||
|
payload.status === 'failure' ? 'failure' :
|
||||||
|
buildStatuses[workflowType].conclusion;
|
||||||
|
buildStatuses[workflowType].url = payload.run_url;
|
||||||
|
buildStatuses[workflowType].target = payload.target;
|
||||||
|
} else {
|
||||||
|
// Create new status entry for real-time updates
|
||||||
|
buildStatuses[workflowType] = {
|
||||||
|
name: payload.workflow_name,
|
||||||
|
status: payload.status === 'in_progress' ? 'in_progress' :
|
||||||
|
payload.status === 'success' ? 'completed' :
|
||||||
|
payload.status === 'failure' ? 'completed' : 'queued',
|
||||||
|
conclusion: payload.status === 'success' ? 'success' :
|
||||||
|
payload.status === 'failure' ? 'failure' : null,
|
||||||
|
url: payload.run_url,
|
||||||
|
runId: payload.run_id,
|
||||||
|
target: payload.target,
|
||||||
|
created_at: new Date().toISOString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`Collected ${allArtifacts.length} total artifacts from all builds`);
|
console.log(`Collected ${allArtifacts.length} total artifacts from all builds`);
|
||||||
|
|
||||||
// Build comment body with progressive status for individual builds
|
// Build comment body with progressive status for individual builds
|
||||||
let commentBody = `## 🔧 Build Status for PR #${pr.number}\n\n`;
|
let commentBody = `## 🔧 Build Status for PR #${pr.number}\n\n`;
|
||||||
commentBody += `🔗 **Commit**: [\`${pr.head.sha.substring(0, 7)}\`](https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${pr.head.sha})\n\n`;
|
commentBody += `🔗 **Commit**: [\`${targetCommitSha.substring(0, 7)}\`](https://github.com/${context.repo.owner}/${context.repo.repo}/commit/${targetCommitSha})\n\n`;
|
||||||
|
|
||||||
|
// Show event context for debugging (only for repository_dispatch)
|
||||||
|
if (context.eventName === 'repository_dispatch') {
|
||||||
|
const payload = context.payload.client_payload;
|
||||||
|
commentBody += `🔔 **Real-time Update**: ${payload.workflow_name} (${payload.target}) - ${payload.status}\n\n`;
|
||||||
|
}
|
||||||
|
|
||||||
// Progressive build status and downloads table
|
// Progressive build status and downloads table
|
||||||
commentBody += `### 📦 Build Artifacts\n\n`;
|
commentBody += `### 📦 Build Artifacts\n\n`;
|
||||||
@@ -164,15 +209,24 @@ jobs:
|
|||||||
|
|
||||||
// Process each expected build target individually
|
// Process each expected build target individually
|
||||||
const buildTargets = [
|
const buildTargets = [
|
||||||
{ name: 'Android Phone', platform: '🤖', device: '📱', pattern: /android.*phone/i },
|
{ name: 'Android Phone', platform: '🤖', device: '📱', workflowType: 'Android', target: 'phone' },
|
||||||
{ name: 'Android TV', platform: '🤖', device: '📺', pattern: /android.*tv/i },
|
{ name: 'Android TV', platform: '🤖', device: '📺', workflowType: 'Android', target: 'tv' },
|
||||||
{ name: 'iOS Phone', platform: '🍎', device: '📱', pattern: /ios.*phone/i },
|
{ name: 'iOS Phone', platform: '🍎', device: '📱', workflowType: 'iOS', target: 'phone' },
|
||||||
{ name: 'iOS TV', platform: '🍎', device: '📺', pattern: /ios.*tv/i }
|
{ name: 'iOS TV', platform: '🍎', device: '📺', workflowType: 'iOS', target: 'tv' }
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const target of buildTargets) {
|
for (const target of buildTargets) {
|
||||||
// Find matching workflow status (using our simplified structure)
|
// Find matching workflow status
|
||||||
const matchingStatus = target.name.includes('Android') ? buildStatuses['Android'] : buildStatuses['iOS'];
|
let matchingStatus = buildStatuses[target.workflowType];
|
||||||
|
|
||||||
|
// For repository_dispatch events, check if this specific target matches
|
||||||
|
if (context.eventName === 'repository_dispatch' && matchingStatus) {
|
||||||
|
const payload = context.payload.client_payload;
|
||||||
|
if (payload.target !== target.target) {
|
||||||
|
// This update is for a different target, show default status
|
||||||
|
matchingStatus = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find matching artifact
|
// Find matching artifact
|
||||||
const matchingArtifact = allArtifacts.find(artifact =>
|
const matchingArtifact = allArtifacts.find(artifact =>
|
||||||
|
|||||||
61
.github/workflows/build-android.yml
vendored
61
.github/workflows/build-android.yml
vendored
@@ -18,6 +18,7 @@ jobs:
|
|||||||
name: 🏗️ Build Android APK
|
name: 🏗️ Build Android APK
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
repository-projects: write
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -25,6 +26,26 @@ jobs:
|
|||||||
target: [phone, tv]
|
target: [phone, tv]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: 📢 Notify artifact comment workflow (started)
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
uses: actions/github-script@v8
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
await github.rest.repos.createDispatchEvent({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
event_type: 'build-started',
|
||||||
|
client_payload: {
|
||||||
|
workflow_name: 'Android APK Build',
|
||||||
|
target: '${{ matrix.target }}',
|
||||||
|
status: 'in_progress',
|
||||||
|
pr_number: ${{ github.event.pull_request.number }},
|
||||||
|
commit_sha: '${{ github.event.pull_request.head.sha }}',
|
||||||
|
run_id: ${{ github.run_id }},
|
||||||
|
run_url: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
- name: 📥 Checkout code
|
- name: 📥 Checkout code
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
with:
|
with:
|
||||||
@@ -91,3 +112,43 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
android/app/build/outputs/apk/release/*.apk
|
android/app/build/outputs/apk/release/*.apk
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|
||||||
|
- name: 🔔 Notify artifact comment workflow (success)
|
||||||
|
if: success() && github.event_name == 'pull_request'
|
||||||
|
uses: actions/github-script@v8
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
await github.rest.repos.createDispatchEvent({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
event_type: 'build-completed',
|
||||||
|
client_payload: {
|
||||||
|
workflow_name: 'Android APK Build',
|
||||||
|
target: '${{ matrix.target }}',
|
||||||
|
status: 'success',
|
||||||
|
pr_number: ${{ github.event.pull_request.number }},
|
||||||
|
commit_sha: '${{ github.event.pull_request.head.sha }}',
|
||||||
|
run_id: ${{ github.run_id }},
|
||||||
|
run_url: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
- name: 🔔 Notify artifact comment workflow (failure)
|
||||||
|
if: failure() && github.event_name == 'pull_request'
|
||||||
|
uses: actions/github-script@v8
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
await github.rest.repos.createDispatchEvent({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
event_type: 'build-failed',
|
||||||
|
client_payload: {
|
||||||
|
workflow_name: 'Android APK Build',
|
||||||
|
target: '${{ matrix.target }}',
|
||||||
|
status: 'failure',
|
||||||
|
pr_number: ${{ github.event.pull_request.number }},
|
||||||
|
commit_sha: '${{ github.event.pull_request.head.sha }}',
|
||||||
|
run_id: ${{ github.run_id }},
|
||||||
|
run_url: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
67
.github/workflows/build-ios.yml
vendored
67
.github/workflows/build-ios.yml
vendored
@@ -9,11 +9,11 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: [develop, master]
|
branches: [develop, master]
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '*.md'
|
- "*.md"
|
||||||
push:
|
push:
|
||||||
branches: [develop, master]
|
branches: [develop, master]
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '*.md'
|
- "*.md"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-ios:
|
build-ios:
|
||||||
@@ -22,14 +22,35 @@ jobs:
|
|||||||
name: 🏗️ Build iOS IPA
|
name: 🏗️ Build iOS IPA
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
repository-projects: write
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
target: [phone]
|
target: [phone]
|
||||||
# target: [phone, tv]
|
# target: [phone, tv]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: 📢 Notify artifact comment workflow (started)
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
uses: actions/github-script@v8
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
await github.rest.repos.createDispatchEvent({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
event_type: 'build-started',
|
||||||
|
client_payload: {
|
||||||
|
workflow_name: 'iOS IPA Build',
|
||||||
|
target: '${{ matrix.target }}',
|
||||||
|
status: 'in_progress',
|
||||||
|
pr_number: ${{ github.event.pull_request.number }},
|
||||||
|
commit_sha: '${{ github.event.pull_request.head.sha }}',
|
||||||
|
run_id: ${{ github.run_id }},
|
||||||
|
run_url: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
- name: 📥 Checkout code
|
- name: 📥 Checkout code
|
||||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
with:
|
with:
|
||||||
@@ -93,3 +114,43 @@ jobs:
|
|||||||
name: streamyfin-ios-${{ matrix.target }}-ipa-${{ env.DATE_TAG }}
|
name: streamyfin-ios-${{ matrix.target }}-ipa-${{ env.DATE_TAG }}
|
||||||
path: build-*.ipa
|
path: build-*.ipa
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|
||||||
|
- name: 🔔 Notify artifact comment workflow (success)
|
||||||
|
if: success() && github.event_name == 'pull_request'
|
||||||
|
uses: actions/github-script@v8
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
await github.rest.repos.createDispatchEvent({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
event_type: 'build-completed',
|
||||||
|
client_payload: {
|
||||||
|
workflow_name: 'iOS IPA Build',
|
||||||
|
target: '${{ matrix.target }}',
|
||||||
|
status: 'success',
|
||||||
|
pr_number: ${{ github.event.pull_request.number }},
|
||||||
|
commit_sha: '${{ github.event.pull_request.head.sha }}',
|
||||||
|
run_id: ${{ github.run_id }},
|
||||||
|
run_url: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
- name: 🔔 Notify artifact comment workflow (failure)
|
||||||
|
if: failure() && github.event_name == 'pull_request'
|
||||||
|
uses: actions/github-script@v8
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
await github.rest.repos.createDispatchEvent({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
event_type: 'build-failed',
|
||||||
|
client_payload: {
|
||||||
|
workflow_name: 'iOS IPA Build',
|
||||||
|
target: '${{ matrix.target }}',
|
||||||
|
status: 'failure',
|
||||||
|
pr_number: ${{ github.event.pull_request.number }},
|
||||||
|
commit_sha: '${{ github.event.pull_request.head.sha }}',
|
||||||
|
run_id: ${{ github.run_id }},
|
||||||
|
run_url: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user