]> git.alsa-project.org Git - alsa-ucm-conf.git/commitdiff
github: workflow: move things to separate alsa-project/github-workflows repo
authorJaroslav Kysela <perex@perex.cz>
Thu, 16 Apr 2026 13:03:33 +0000 (15:03 +0200)
committerJaroslav Kysela <perex@perex.cz>
Thu, 16 Apr 2026 13:04:44 +0000 (15:04 +0200)
It is a preparation to be reused for other ALSA repos.

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
.github/label-descriptions.yml [deleted file]
.github/workflows/label-automation.yml
.github/workflows/pr-validation.yml
.github/workflows/reusable-label-commenter.yml [deleted file]
.github/workflows/reusable-sob-validator.yml [deleted file]

diff --git a/.github/label-descriptions.yml b/.github/label-descriptions.yml
deleted file mode 100644 (file)
index 6cd51e3..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-# Label descriptions configuration
-# Each label can have a description that will be posted as a comment when the label is applied
-
-labels:
-  - name: kernel driver
-    description: |
-      ## ALSA Linux kernel driver work
-
-      **Note:** This issue does not appear to be related to this repository, but rather seems to be an ALSA kernel driver issue.
-
-      Please direct ALSA driver related discussions to the linux-sound@vger.kernel.org mailing list.
-
-      **Bugtracker:** https://bugzilla.kernel.org (Audio component)
-
-      For kernel patches, please see: https://www.kernel.org/doc/html/latest/process/submitting-patches.html
-
-  - name: signed off by
-    description: |
-      ## Missing correct Signed-off-by line
-
-      This pull request has commits that are missing proper `Signed-off-by` lines or use invalid email addresses.
-
-      **Requirements:**
-      - Each commit must include at least one `Signed-off-by: Your Name <your.email@example.com>` line
-      - Commit author email must appear in at least one Signed-off-by line
-      - Commit committer email must appear in at least one Signed-off-by line (if not a GitHub bot)
-      - Multiple Signed-off-by lines are allowed for co-authored commits
-      - Anonymous GitHub emails (like `@users.noreply.github.com`) are not allowed
-      - The Signed-off-by line indicates that you agree to the Developer Certificate of Origin (DCO)
-
-      **How to fix:**
-      ```bash
-      # Configure your git identity first (if needed):
-      git config user.name "Your Name"
-      git config user.email "your.email@example.com"
-
-      # For the last commit:
-      git commit --amend --signoff
-
-      # For multiple commits, use interactive rebase:
-      git rebase -i HEAD~N --signoff
-
-      # For co-authored commits, add multiple Signed-off-by lines manually:
-      git commit --amend
-      # Then add in the commit message:
-      # Signed-off-by: Author One <author1@example.com>
-      # Signed-off-by: Author Two <author2@example.com>
-
-      # Then force push:
-      git push --force-with-lease
-      ```
-
-      **Reference:** [Developer Certificate of Origin](https://developercertificate.org/)
-
-# Signed-off-by validation configuration
-sob_validation:
-  # Email patterns to deny (supports wildcards)
-  denied_emails:
-    - '*@users.noreply.github.com'
-    # Add more patterns as needed:
-    # - '*@example-blocked-domain.com'
-    # - 'noreply@*'
index 783a33431adec9306f55ccf190ac2e64c23d4502..71a987644b97aab37fc51298fe106b4a1d0bb61c 100644 (file)
@@ -1,5 +1,8 @@
-# Example workflow for using the label commenter
+ Example workflow for using the label commenter
 # Place this file in your repository at: .github/workflows/label-automation.yml
+#
+# You also need to create .github/label-descriptions.yml in your repository
+# Example config: https://github.com/alsa-project/github-workflows/blob/main/repo/config/label-descriptions.yml
 
 name: Label Automation
 
@@ -13,11 +16,14 @@ on:
 
 jobs:
   handle-label:
-    uses: ./.github/workflows/reusable-label-commenter.yml
+    uses: alsa-project/github-workflows/repo/workflows/label-commenter.yml@main
     permissions:
       contents: read
       pull-requests: write
       issues: write
     with:
-      config-path: '.github/label-descriptions.yml'
+      # Path to your local config file OR URL to remote config (required)
+      config-path: 'https://raw.githubusercontent.com/alsa-project/github-workflows/main/repo/config/label-descriptions.yml'
+      # Local file example: '.github/label-descriptions.yml'
+      # Remote URL example: 'https://raw.githubusercontent.com/alsa-project/github-workflows/main/repo/config/label-descriptions.yml'
     secrets: inherit
index bbce7031627ef161c76c18dca3dac146ad554d77..2fab1a49038262565fb7f3a0906ced1963589e5f 100644 (file)
@@ -1,5 +1,8 @@
 # Example workflow for automatic Signed-off-by validation
 # Place this file in your repository at: .github/workflows/pr-validation.yml
+#
+# You also need to create .github/label-descriptions.yml in your repository
+# Example config: https://github.com/alsa-project/github-workflows/blob/main/repo/config/label-descriptions.yml
 
 name: PR Validation
 
@@ -17,13 +20,16 @@ on:
 
 jobs:
   validate-commits:
-    uses: ./.github/workflows/reusable-sob-validator.yml
+    uses: alsa-project/github-workflows/repo/workflows/sob-validator.yml@main
     permissions:
       contents: read
       pull-requests: write
       issues: write
     with:
-      config-path: '.github/label-descriptions.yml'
+      # Path to your local config file OR URL to remote config (required)
+      config-path: 'https://raw.githubusercontent.com/alsa-project/github-workflows/main/repo/config/label-descriptions.yml'
+      # Local file example: '.github/label-descriptions.yml'
+      # Remote URL example: 'https://raw.githubusercontent.com/alsa-project/github-workflows/main/repo/config/label-descriptions.yml'
       sob-label: 'signed off by'
       pr-number: ${{ github.event_name == 'workflow_dispatch' && format('{0}', inputs.pr_number) || '' }}
     secrets: inherit
diff --git a/.github/workflows/reusable-label-commenter.yml b/.github/workflows/reusable-label-commenter.yml
deleted file mode 100644 (file)
index ac7638f..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-name: Reusable Label Commenter
-
-on:
-  workflow_call:
-    inputs:
-      config-path:
-        description: 'Path to label descriptions config file'
-        required: false
-        type: string
-        default: '.github/label-descriptions.yml'
-
-jobs:
-  add-label-comment:
-    runs-on: ubuntu-latest
-    permissions:
-      contents: read
-      pull-requests: write
-      issues: write
-    steps:
-      - name: Checkout repository
-        uses: actions/checkout@v4
-
-      - name: Read and parse config
-        id: read-config
-        run: |
-          if [ ! -f "${{ inputs.config-path }}" ]; then
-            echo "exists=false" >> $GITHUB_OUTPUT
-            echo "Warning: Config file ${{ inputs.config-path }} not found"
-            exit 0
-          fi
-
-          echo "exists=true" >> $GITHUB_OUTPUT
-
-          # Convert YAML to JSON using Python
-          python3 << 'PYTHON_EOF' > /tmp/config.json
-          import yaml
-          import json
-          with open('${{ inputs.config-path }}', 'r') as f:
-            config = yaml.safe_load(f)
-          print(json.dumps(config))
-          PYTHON_EOF
-
-          # Store JSON as output (escaped for multiline)
-          echo "config<<EOF" >> $GITHUB_OUTPUT
-          cat /tmp/config.json >> $GITHUB_OUTPUT
-          echo "EOF" >> $GITHUB_OUTPUT
-
-      - name: Handle label action
-        uses: actions/github-script@v7
-        with:
-          github-token: ${{ secrets.GITHUB_TOKEN }}
-          script: |
-            // Get the label and action
-            const label = context.payload.label.name;
-            const action = context.payload.action;
-
-            // Check if issue or PR
-            const issueNumber = context.payload.issue?.number || context.payload.pull_request?.number;
-            if (!issueNumber) {
-              console.log('No issue or PR number found');
-              return;
-            }
-
-            // Create unique identifier for this label comment
-            const commentId = `<!-- label-commenter:${label} -->`;
-
-            // Get existing comments
-            const { data: comments } = await github.rest.issues.listComments({
-              owner: context.repo.owner,
-              repo: context.repo.repo,
-              issue_number: issueNumber,
-            });
-
-            // Find existing comment with this label ID
-            const existingComment = comments.find(comment =>
-              comment.body?.includes(commentId)
-            );
-
-            if (action === 'unlabeled') {
-              // Label was removed - delete the comment if it exists
-              if (existingComment) {
-                await github.rest.issues.deleteComment({
-                  owner: context.repo.owner,
-                  repo: context.repo.repo,
-                  comment_id: existingComment.id,
-                });
-                console.log(`Deleted comment for removed label: ${label}`);
-              } else {
-                console.log(`No comment found for removed label: ${label}`);
-              }
-            } else if (action === 'labeled') {
-              // Label was added - add or update comment
-              const config = JSON.parse(process.env.CONFIG_JSON || '{}');
-
-              // Find description for this label
-              const labelConfig = config.labels?.find(l => l.name === label);
-
-              if (!labelConfig || !labelConfig.description) {
-                console.log(`No description configured for label: ${label}`);
-                return;
-              }
-
-              const commentBody = `${commentId}\n${labelConfig.description}`;
-
-              if (existingComment) {
-                // Update existing comment
-                await github.rest.issues.updateComment({
-                  owner: context.repo.owner,
-                  repo: context.repo.repo,
-                  comment_id: existingComment.id,
-                  body: commentBody,
-                });
-                console.log(`Updated comment for label: ${label}`);
-              } else {
-                // Create new comment
-                await github.rest.issues.createComment({
-                  owner: context.repo.owner,
-                  repo: context.repo.repo,
-                  issue_number: issueNumber,
-                  body: commentBody,
-                });
-                console.log(`Created comment for label: ${label}`);
-              }
-            }
-        env:
-          CONFIG_JSON: ${{ steps.read-config.outputs.config }}
diff --git a/.github/workflows/reusable-sob-validator.yml b/.github/workflows/reusable-sob-validator.yml
deleted file mode 100644 (file)
index 97cc681..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-name: Reusable Signed-off-by Validator
-
-on:
-  workflow_call:
-    inputs:
-      config-path:
-        description: 'Path to label descriptions config file'
-        required: false
-        type: string
-        default: '.github/label-descriptions.yml'
-      sob-label:
-        description: 'Label to add when SOB is missing or invalid'
-        required: false
-        type: string
-        default: 'signed off by'
-      pr-number:
-        description: 'PR number to validate (optional, auto-detects from event if not provided)'
-        required: false
-        type: string
-        default: ''
-
-jobs:
-  validate-signedoff:
-    runs-on: ubuntu-latest
-    permissions:
-      contents: read
-      pull-requests: write
-      issues: write
-    steps:
-      - name: Checkout repository
-        uses: actions/checkout@v4
-        with:
-          fetch-depth: 0
-
-      - name: Determine PR number
-        id: pr-number
-        uses: actions/github-script@v7
-        with:
-          script: |
-            // Get PR number from input (if manually triggered) or from event
-            const inputPrNumber = '${{ inputs.pr-number }}';
-            const prNumber = (inputPrNumber && inputPrNumber.trim() !== '')
-              ? inputPrNumber
-              : context.payload.pull_request?.number;
-
-            if (!prNumber) {
-              core.setFailed('No PR number available from input or event');
-              return;
-            }
-            core.setOutput('number', prNumber);
-            console.log(`Using PR number: ${prNumber}`);
-
-      - name: Read and parse config
-        id: read-config
-        run: |
-          if [ ! -f "${{ inputs.config-path }}" ]; then
-            echo "exists=false" >> $GITHUB_OUTPUT
-            echo "{}" > /tmp/config.json
-          else
-            echo "exists=true" >> $GITHUB_OUTPUT
-            # Convert YAML to JSON using Python
-            python3 << 'PYTHON_EOF' > /tmp/config.json
-          import yaml
-          import json
-          with open('${{ inputs.config-path }}', 'r') as f:
-            config = yaml.safe_load(f)
-          print(json.dumps(config))
-          PYTHON_EOF
-          fi
-
-          # Store JSON as output (escaped for multiline)
-          echo "config<<EOF" >> $GITHUB_OUTPUT
-          cat /tmp/config.json >> $GITHUB_OUTPUT
-          echo "EOF" >> $GITHUB_OUTPUT
-
-      - name: Validate Signed-off-by
-        id: validate
-        uses: actions/github-script@v7
-        with:
-          github-token: ${{ secrets.GITHUB_TOKEN }}
-          script: |
-            // Parse config from JSON
-            const config = JSON.parse(process.env.CONFIG_JSON);
-            let deniedEmails = config.sob_validation?.denied_emails || [];
-
-            // Add default denied patterns
-            if (!deniedEmails.includes('*@users.noreply.github.com')) {
-              deniedEmails.push('*@users.noreply.github.com');
-            }
-
-            const prNumber = ${{ steps.pr-number.outputs.number }};
-
-            // Get all commits in the PR
-            const { data: commits } = await github.rest.pulls.listCommits({
-              owner: context.repo.owner,
-              repo: context.repo.repo,
-              pull_number: prNumber,
-            });
-
-            const issues = [];
-
-            for (const commit of commits) {
-              const message = commit.commit.message;
-              const sha = commit.sha.substring(0, 7);
-              const authorEmail = commit.commit.author.email;
-              const committerEmail = commit.commit.committer.email;
-
-              // Find all Signed-off-by lines (case-insensitive)
-              const sobPattern = /^Signed-off-by:\s+(.+)\s+<(.+)>$/gim;
-              const sobMatches = [...message.matchAll(sobPattern)];
-
-              if (sobMatches.length === 0) {
-                issues.push(`- Commit ${sha}: Missing Signed-off-by line`);
-                continue;
-              }
-
-              // Extract all SOB emails
-              const sobEmails = sobMatches.map(match => match[2]);
-
-              // Check if author email is in at least one Signed-off-by line
-              if (!sobEmails.includes(authorEmail)) {
-                issues.push(`- Commit ${sha}: Commit author email (${authorEmail}) not found in any Signed-off-by line`);
-                continue;
-              }
-
-              // Check if committer email is in at least one Signed-off-by line
-              // (Skip check for GitHub web-flow and noreply bots which are common for web commits)
-              const isGitHubBot = committerEmail.includes('noreply.github.com') ||
-                                  committerEmail === 'noreply@github.com';
-              if (!isGitHubBot && !sobEmails.includes(committerEmail)) {
-                issues.push(`- Commit ${sha}: Commit committer email (${committerEmail}) not found in any Signed-off-by line`);
-                continue;
-              }
-
-              // Check all SOB emails against denied patterns
-              let deniedEmailFound = false;
-              for (const sobEmail of sobEmails) {
-                for (const pattern of deniedEmails) {
-                  const regex = new RegExp('^' + pattern.replace('*', '.*') + '$');
-                  if (regex.test(sobEmail)) {
-                    issues.push(`- Commit ${sha}: Invalid email in Signed-off-by: ${sobEmail}`);
-                    deniedEmailFound = true;
-                    break;
-                  }
-                }
-                if (deniedEmailFound) break;
-              }
-              if (deniedEmailFound) continue;
-
-              // Check author email against denied patterns
-              let authorDenied = false;
-              for (const pattern of deniedEmails) {
-                const regex = new RegExp('^' + pattern.replace('*', '.*') + '$');
-                if (regex.test(authorEmail)) {
-                  issues.push(`- Commit ${sha}: Invalid commit author email: ${authorEmail}`);
-                  authorDenied = true;
-                  break;
-                }
-              }
-              if (authorDenied) continue;
-
-              // Check committer email against denied patterns (skip GitHub bots)
-              if (!isGitHubBot) {
-                for (const pattern of deniedEmails) {
-                  const regex = new RegExp('^' + pattern.replace('*', '.*') + '$');
-                  if (regex.test(committerEmail)) {
-                    issues.push(`- Commit ${sha}: Invalid commit committer email: ${committerEmail}`);
-                    break;
-                  }
-                }
-              }
-            }
-
-            // Store results
-            core.setOutput('has_issues', issues.length > 0);
-            core.setOutput('issues', issues.join('\n'));
-
-            return issues.length > 0;
-        env:
-          CONFIG_JSON: ${{ steps.read-config.outputs.config }}
-
-      - name: Add label if issues found
-        if: steps.validate.outputs.has_issues == 'true'
-        uses: actions/github-script@v7
-        with:
-          github-token: ${{ secrets.GITHUB_TOKEN }}
-          script: |
-            await github.rest.issues.addLabels({
-              owner: context.repo.owner,
-              repo: context.repo.repo,
-              issue_number: ${{ steps.pr-number.outputs.number }},
-              labels: ['${{ inputs.sob-label }}'],
-            });
-
-      - name: Add comment with issues
-        if: steps.validate.outputs.has_issues == 'true'
-        uses: actions/github-script@v7
-        with:
-          github-token: ${{ secrets.GITHUB_TOKEN }}
-          script: |
-            const commentId = '<!-- sob-validator -->';
-            const issues = process.env.SOB_ISSUES;
-
-            // Try to get custom message from config
-            let customMessage = '';
-            const config = JSON.parse(process.env.CONFIG_JSON);
-            const labelConfig = config.labels?.find(l => l.name === '${{ inputs.sob-label }}');
-            if (labelConfig?.description) {
-              customMessage = '\n\n' + labelConfig.description;
-            }
-
-            const commentBody = commentId + '\n' +
-              '## ⚠️ Signed-off-by Validation Issues\n\n' +
-              'The following commits have issues with their Signed-off-by lines:\n\n' +
-              issues + '\n\n' +
-              'Please add a proper `Signed-off-by: Your Name <your.email@example.com>` line to each commit message.' +
-              customMessage;
-
-            // Check for existing comment
-            const { data: comments } = await github.rest.issues.listComments({
-              owner: context.repo.owner,
-              repo: context.repo.repo,
-              issue_number: ${{ steps.pr-number.outputs.number }},
-            });
-
-            const existingComment = comments.find(c => c.body?.includes(commentId));
-
-            if (existingComment) {
-              await github.rest.issues.updateComment({
-                owner: context.repo.owner,
-                repo: context.repo.repo,
-                comment_id: existingComment.id,
-                body: commentBody,
-              });
-            } else {
-              await github.rest.issues.createComment({
-                owner: context.repo.owner,
-                repo: context.repo.repo,
-                issue_number: ${{ steps.pr-number.outputs.number }},
-                body: commentBody,
-              });
-            }
-        env:
-          SOB_ISSUES: ${{ steps.validate.outputs.issues }}
-          CONFIG_JSON: ${{ steps.read-config.outputs.config }}
-
-      - name: Remove label and comment if no issues
-        if: steps.validate.outputs.has_issues == 'false'
-        uses: actions/github-script@v7
-        continue-on-error: true
-        with:
-          github-token: ${{ secrets.GITHUB_TOKEN }}
-          script: |
-            const prNumber = parseInt('${{ steps.pr-number.outputs.number }}', 10);
-            const labelName = '${{ inputs.sob-label }}';
-
-            // Remove label
-            try {
-              await github.rest.issues.removeLabel({
-                owner: context.repo.owner,
-                repo: context.repo.repo,
-                issue_number: prNumber,
-                name: labelName,
-              });
-              console.log(`Removed label: ${labelName}`);
-            } catch (error) {
-              if (error.status === 404) {
-                console.log('Label not present or already removed');
-              } else {
-                console.log(`Error removing label: ${error.message}`);
-              }
-            }
-
-            // Remove validation comment if it exists
-            try {
-              const commentId = '<!-- sob-validator -->';
-              const { data: comments } = await github.rest.issues.listComments({
-                owner: context.repo.owner,
-                repo: context.repo.repo,
-                issue_number: prNumber,
-              });
-
-              const existingComment = comments.find(c => c.body?.includes(commentId));
-
-              if (existingComment) {
-                await github.rest.issues.deleteComment({
-                  owner: context.repo.owner,
-                  repo: context.repo.repo,
-                  comment_id: existingComment.id,
-                });
-                console.log('Removed validation comment');
-              }
-            } catch (error) {
-              console.log(`Error removing comment: ${error.message}`);
-            }