diff --git a/__tests__/infrastructure/ci-change.test.js b/__tests__/infrastructure/ci-change.test.js new file mode 100644 index 0000000..1ad4457 --- /dev/null +++ b/__tests__/infrastructure/ci-change.test.js @@ -0,0 +1,61 @@ +const rule = require('../../src/rules/ci/ci-change'); + +describe('CI Change Rule', () => { + it('labels for GitHub Actions workflow', () => { + const files = [{ filename: '.github/workflows/build.yml' }]; + const labels = rule({ files, pr: {}, enableDebug: false }); + expect(labels).toContain('ci-change'); + }); + + it('labels for CircleCI config', () => { + const files = [{ filename: '.circleci/config.yml' }]; + const labels = rule({ files, pr: {}, enableDebug: false }); + expect(labels).toContain('ci-change'); + }); + + it('labels for Jenkinsfile', () => { + const files = [{ filename: 'ci/Jenkinsfile' }]; + const labels = rule({ files, pr: {}, enableDebug: false }); + expect(labels).toContain('ci-change'); + }); + + it('labels for Azure Pipelines', () => { + const files = [{ filename: 'azure-pipelines.yml' }]; + const labels = rule({ files, pr: {}, enableDebug: false }); + expect(labels).toContain('ci-change'); + }); + + it('labels for GitLab CI', () => { + const files = [{ filename: 'root/gitlab-ci.yml' }]; + const labels = rule({ files, pr: {}, enableDebug: false }); + expect(labels).toContain('ci-change'); + }); + + it('labels for Bitrise', () => { + const files = [{ filename: 'config/bitrise.yml' }]; + const labels = rule({ files, pr: {}, enableDebug: false }); + expect(labels).toContain('ci-change'); + }); + + it('does not label for non-ci files', () => { + const files = [{ filename: 'src/index.ts' }]; + const labels = rule({ files, pr: {}, enableDebug: false }); + expect(labels).toEqual([]); + }); + + it('handles empty files array', () => { + const labels = rule({ files: [], pr: {}, enableDebug: false }); + expect(labels).toEqual([]); + }); + + it('handles null filename', () => { + const files = [{ filename: null }]; + const labels = rule({ files, pr: {}, enableDebug: false }); + expect(labels).toEqual([]); + }); + + it('handles debug mode', () => { + const files = [{ filename: '.github/workflows/test.yml' }]; + expect(() => rule({ files, pr: {}, enableDebug: true })).not.toThrow(); + }); +}); diff --git a/src/rules/ci/ci-change.js b/src/rules/ci/ci-change.js new file mode 100644 index 0000000..95d4e13 --- /dev/null +++ b/src/rules/ci/ci-change.js @@ -0,0 +1,46 @@ +/** + * CI Workflow Change Rule + * + * Adds `ci-change` if CI pipeline/workflow files are modified. + */ + +module.exports = function ciChangeRule({ files, pr, enableDebug }) { + const labels = []; + + const patterns = [ + /^\.github\/workflows\//i, + /^\.circleci\//i, + /(^|\/)Jenkinsfile$/i, + /(^|\/)azure-pipelines\.ya?ml$/i, + /(^|\/)gitlab-ci\.ya?ml$/i, + /(^|\/)bitrise\.ya?ml$/i + ]; + + const detected = (files || []).some(f => { + const name = (f && f.filename ? String(f.filename) : '').toLowerCase(); + return name && patterns.some(rx => rx.test(name)); + }); + + if (detected) { + labels.push('ci-change'); + } + + if (enableDebug) { + console.log(`[CI Change Rule] → ${labels.join(', ') || 'none'}`); + } + + return labels; +}; + +module.exports.metadata = { + name: 'CI Workflow Changes', + description: 'Detects modifications to CI workflows/pipelines', + labels: [ + { name: 'ci-change', color: '0075CA', description: 'CI workflow changed' } + ], + author: 'pr-auto-labeler', + version: '1.0.0', + category: 'infrastructure' +}; + +