1+ name : 🎃 Hacktoberfest Auto-Labeling
2+
3+ on :
4+ pull_request :
5+ branches : [ main ]
6+ types : [opened, synchronize]
7+ issues :
8+ types : [opened]
9+
10+ permissions :
11+ contents : read
12+ pull-requests : write
13+ issues : write
14+
15+ jobs :
16+ auto-label :
17+ runs-on : ubuntu-latest
18+
19+ steps :
20+ - name : 📥 Checkout code
21+ uses : actions/checkout@v4
22+ with :
23+ fetch-depth : 0
24+
25+ - name : 🔍 Get changed files
26+ if : github.event_name == 'pull_request'
27+ id : changed-files
28+ uses : tj-actions/changed-files@v40
29+
30+ - name : 🎃 Add Hacktoberfest labels and welcome contributors
31+ if : github.event_name == 'pull_request'
32+ uses : actions/github-script@v7
33+ with :
34+ script : |
35+ try {
36+ // Get changed files
37+ const { data: changedFiles } = await github.rest.pulls.listFiles({
38+ owner: context.repo.owner,
39+ repo: context.repo.repo,
40+ pull_number: context.payload.pull_request.number
41+ });
42+
43+ const files = changedFiles.map(file => file.filename);
44+ const labels = ['hacktoberfest'];
45+
46+ console.log(`Processing ${files.length} changed files`);
47+
48+ // Determine contribution type
49+ const hasAlgorithms = files.some(f => f.includes('/algorithms/'));
50+ const hasDataStructures = files.some(f => f.includes('/data_structures/'));
51+ const hasDP = files.some(f => f.includes('/dynamic_programming/'));
52+ const hasProjects = files.some(f => f.includes('/projects/'));
53+ const hasDocumentation = files.some(f => f.includes('README') || f.includes('.md'));
54+ const hasNewLanguage = files.some(f =>
55+ !f.startsWith('C/') &&
56+ !f.startsWith('CPP/') &&
57+ !f.startsWith('Java/') &&
58+ !f.startsWith('Python/') &&
59+ /\.(c|cpp|java|py|js|ts|go|rs|kt|swift|php|rb|cs|dart|scala)$/.test(f)
60+ );
61+
62+ // Add specific labels
63+ if (hasAlgorithms) labels.push('algorithms');
64+ if (hasDataStructures) labels.push('data-structures');
65+ if (hasDP) labels.push('dynamic-programming');
66+ if (hasProjects) labels.push('projects');
67+ if (hasDocumentation) labels.push('documentation');
68+ if (hasNewLanguage) labels.push('new-language');
69+
70+ // Language-specific labels
71+ const languages = {
72+ 'C/': 'lang:c',
73+ 'CPP/': 'lang:cpp',
74+ 'Java/': 'lang:java',
75+ 'Python/': 'lang:python',
76+ 'JavaScript/': 'lang:javascript',
77+ 'Go/': 'lang:go',
78+ 'Rust/': 'lang:rust',
79+ 'Kotlin/': 'lang:kotlin',
80+ 'Swift/': 'lang:swift',
81+ 'PHP/': 'lang:php',
82+ 'Ruby/': 'lang:ruby',
83+ 'CSharp/': 'lang:csharp',
84+ 'Dart/': 'lang:dart',
85+ 'Scala/': 'lang:scala'
86+ };
87+
88+ for (const [dir, label] of Object.entries(languages)) {
89+ if (files.some(f => f.startsWith(dir))) {
90+ labels.push(label);
91+ }
92+ }
93+
94+ // Difficulty estimation
95+ const fileCount = files.length;
96+ if (fileCount === 1) labels.push('good first issue');
97+ else if (fileCount <= 3) labels.push('easy');
98+ else if (fileCount <= 7) labels.push('medium');
99+ else labels.push('hard');
100+
101+ // Check if first-time contributor (with error handling)
102+ let isFirstTime = false;
103+ try {
104+ const { data: commits } = await github.rest.repos.listCommits({
105+ owner: context.repo.owner,
106+ repo: context.repo.repo,
107+ author: context.payload.pull_request.user.login,
108+ per_page: 5
109+ });
110+
111+ if (commits.length <= 1) {
112+ isFirstTime = true;
113+ labels.push('first-time-contributor');
114+ }
115+ } catch (error) {
116+ console.log('Could not check contributor history:', error.message);
117+ isFirstTime = true;
118+ labels.push('first-time-contributor');
119+ }
120+
121+ // Apply labels
122+ await github.rest.issues.addLabels({
123+ owner: context.repo.owner,
124+ repo: context.repo.repo,
125+ issue_number: context.payload.pull_request.number,
126+ labels: labels
127+ });
128+
129+ console.log(`Applied labels: ${labels.join(', ')}`);
130+
131+ // Welcome first-time contributors
132+ if (isFirstTime) {
133+ const welcomeMessage = `🎉 **Welcome to the DSA Code Repository!**
134+
135+ Thank you @${context.payload.pull_request.user.login} for your first contribution!
136+
137+ 🎃 **Hacktoberfest 2025**: This PR counts towards Hacktoberfest!
138+
139+ 📋 **Next Steps**:
140+ - Our team will review your PR shortly
141+ - Make sure your code follows our [contribution guidelines](./CONTRIBUTING.md)
142+ - Check our [Hall of Fame](./HALL_OF_FAME.md) to see where you'll be featured!
143+
144+ 🚀 **Pro Tips**:
145+ - Add clear comments to your code
146+ - Include time/space complexity analysis
147+ - Test your implementation with sample inputs
148+
149+ Thanks for contributing to open source! 🌟`;
150+
151+ await github.rest.issues.createComment({
152+ owner: context.repo.owner,
153+ repo: context.repo.repo,
154+ issue_number: context.payload.pull_request.number,
155+ body: welcomeMessage
156+ });
157+
158+ console.log('Welcome message posted for first-time contributor');
159+ }
160+
161+ } catch (error) {
162+ console.error('Error in labeling workflow:', error);
163+ try {
164+ await github.rest.issues.addLabels({
165+ owner: context.repo.owner,
166+ repo: context.repo.repo,
167+ issue_number: context.payload.pull_request.number,
168+ labels: ['hacktoberfest']
169+ });
170+ } catch (fallbackError) {
171+ console.error('Fallback labeling also failed:', fallbackError);
172+ }
173+ }
174+
175+ - name : 🏷️ Add Hacktoberfest label to issues
176+ if : github.event_name == 'issues'
177+ uses : actions/github-script@v7
178+ with :
179+ script : |
180+ try {
181+ const labels = ['hacktoberfest'];
182+
183+ // Check issue content for categories
184+ const body = context.payload.issue.body?.toLowerCase() || '';
185+ const title = context.payload.issue.title?.toLowerCase() || '';
186+
187+ if (body.includes('algorithm') || title.includes('algorithm')) labels.push('algorithms');
188+ if (body.includes('data structure') || title.includes('data structure')) labels.push('data-structures');
189+ if (body.includes('bug') || title.includes('bug')) labels.push('bug');
190+ if (body.includes('enhancement') || title.includes('enhancement')) labels.push('enhancement');
191+ if (body.includes('documentation') || title.includes('doc')) labels.push('documentation');
192+ if (body.includes('language') || title.includes('language')) labels.push('new-language');
193+
194+ // Add beginner-friendly label for certain keywords
195+ if (body.includes('beginner') || body.includes('first') || body.includes('easy')) {
196+ labels.push('good first issue');
197+ }
198+
199+ await github.rest.issues.addLabels({
200+ owner: context.repo.owner,
201+ repo: context.repo.repo,
202+ issue_number: context.payload.issue.number,
203+ labels: labels
204+ });
205+
206+ console.log(`Applied issue labels: ${labels.join(', ')}`);
207+
208+ } catch (error) {
209+ console.error('Error labeling issue:', error);
210+ }
0 commit comments