From dd82a90f7ea168d30e444a0b813b484fe0fa99d3 Mon Sep 17 00:00:00 2001 From: BekahHW Date: Fri, 5 Sep 2025 12:47:52 -0400 Subject: [PATCH 1/6] Add new process and move contributors --- .github/PULL_REQUEST_TEMPLATE.md | 69 ++- .../workflows/intro_course_contributor.yml | 2 +- .github/workflows/update-contributors.yml | 141 +++++ .github/workflows/validate-contributors.yml | 52 ++ .github/workflows/validate-pr.yml | 121 ++++ .github/workflows/welcome-new-contributor.yml | 52 ++ .gitignore | 3 +- CONTRIBUTING.md | 16 +- README.md | 532 +++++------------- contributors/.gitkeep | 2 + contributors/02zeda.json | 11 + contributors/ATREAY.json | 17 + contributors/Aditya-Kumar-Sahu.json | 40 ++ contributors/Aftar-Ahmad-Sami.json | 13 + contributors/Ajiboso-Adeola.json | 13 + contributors/Akintademuyiwa24.json | 14 + contributors/Alejandro-Saavedra.json | 8 + contributors/Alex87464.json | 12 + contributors/Alfred-Emmanuel.json | 11 + contributors/Ali-Ahmed-Mohamed.json | 8 + contributors/Alok-Jadhao.json | 9 + contributors/Alz3bi.json | 14 + contributors/AngelMancilla.json | 21 + contributors/Ankit8848.json | 9 + contributors/Ant-Shell.json | 10 + contributors/ArchILLtect.json | 10 + contributors/Aswin-22.json | 24 + contributors/Axfez.json | 12 + contributors/Ayamigah16.json | 23 + contributors/AyushShuklaIIIT.json | 8 + contributors/BekahHW.json | 25 + contributors/Bradondev.json | 9 + contributors/BrianMunsey.json | 11 + contributors/BrodyWills.json | 9 + contributors/C-o-m-o-n.json | 12 + contributors/CBID2.json | 28 + contributors/CODINATA.json | 9 + contributors/ChiaBeaCode.json | 11 + contributors/ChinmayBagad.json | 15 + contributors/CodeLikeAGirl29.json | 18 + contributors/CynthiaWahome.json | 13 + contributors/DChitale.json | 37 ++ contributors/Emmarie-Ahtunan.json | 13 + contributors/Esaius2058.json | 33 ++ contributors/EthenThinkful.json | 12 + contributors/Ezzywealth.json | 26 + contributors/FahimJadid.json | 17 + contributors/Fatima-Abdirashid.json | 36 ++ contributors/Firdous2307.json | 14 + contributors/Franklyn883.json | 11 + contributors/Ghaith-Rain.json | 11 + contributors/Guruscod.json | 9 + contributors/Haimantika.json | 10 + contributors/Hardik-S-003.json | 10 + contributors/Harshdev10.json | 20 + contributors/Harshh18.json | 18 + contributors/Hellkryptonium.json | 11 + contributors/IM-Suryakant-Kumar.json | 9 + contributors/IbnuAlii.json | 8 + contributors/Id8987.json | 13 + contributors/Iqra-Issack.json | 9 + contributors/Izuchii.json | 10 + contributors/JaisonBinns.json | 40 ++ contributors/JayRKyd.json | 9 + contributors/JesseRWeigel.json | 13 + contributors/JingjieGao.json | 8 + contributors/JohnMwendwa.json | 14 + contributors/JulesRules65.json | 8 + contributors/Justin-WebDev.json | 27 + contributors/Kaanan2000.json | 15 + contributors/Kamari93.json | 11 + contributors/Kaz-Smino.json | 40 ++ contributors/Ken-Musau.json | 9 + contributors/Lmdingi.json | 9 + contributors/Lor1138.json | 26 + contributors/Luca1905.json | 10 + contributors/LuisCFunes.json | 10 + contributors/Lymah123.json | 17 + contributors/MadAvidCoder.json | 9 + contributors/ManuelaFlores.json | 17 + contributors/MarcellaHarr.json | 13 + contributors/MayankChandratre1.json | 10 + contributors/MehediMubin.json | 9 + contributors/Metratrj.json | 12 + contributors/Mi1king.json | 15 + contributors/MohamedAliJmal.json | 20 + contributors/Msrimpson.json | 8 + contributors/Mugabe000.json | 15 + contributors/Muniir1.json | 8 + contributors/Muskan-Seth03.json | 12 + contributors/Muyixone.json | 15 + contributors/Muzammil-cyber.json | 9 + contributors/Nabinbista12.json | 8 + contributors/Neerajrawat123.json | 8 + contributors/NeverGray.json | 11 + contributors/Obasoro.json | 23 + contributors/OluwabukolaU.json | 11 + contributors/Pondy007.json | 11 + contributors/QUxPTA.json | 12 + contributors/Quartel.json | 9 + contributors/README.md | 42 ++ contributors/RafaelJohn9.json | 18 + contributors/RayX81194.json | 14 + contributors/Rijan-Joshi.json | 9 + contributors/Sadeedpv.json | 17 + contributors/SamarMst.json | 12 + contributors/Satoshi-Sh.json | 10 + contributors/Shin1ma.json | 10 + contributors/SimonGideon.json | 8 + contributors/SkipPharaoh.json | 18 + contributors/SnowyCrest.json | 8 + contributors/Solenessa.json | 19 + contributors/SoufianeJm.json | 9 + contributors/Spcxx.json | 13 + contributors/Suei43.json | 21 + contributors/Suldana.json | 8 + contributors/Sunny-unik.json | 18 + contributors/SusanGithaigaN.json | 12 + contributors/SushiJ.json | 8 + contributors/Tamale1.json | 10 + contributors/TanishqV5.json | 16 + contributors/Tawan-B.json | 24 + contributors/Teemamin.json | 12 + contributors/TejsinghDhaosriya.json | 13 + contributors/TheOphige.json | 10 + contributors/TomasDarquier.json | 12 + contributors/ToniBirat7.json | 17 + contributors/ToobaJamal.json | 29 + contributors/Ufidtech.json | 10 + contributors/ValLee4.json | 8 + contributors/ValarieOyieke.json | 12 + contributors/Vamsi-344.json | 16 + contributors/Vikingu-del.json | 11 + contributors/VirginieLemaire.json | 12 + contributors/WassCodeur.json | 18 + contributors/Woytsekj.json | 10 + contributors/WybsonSantana.json | 8 + contributors/YoungGunner14.json | 8 + contributors/ZeeshanMukhtar1.json | 16 + contributors/Zier0Code.json | 9 + contributors/acskii.json | 9 + contributors/adaniel105.json | 12 + contributors/adiati98.json | 16 + contributors/adiazt01.json | 8 + contributors/aerg04.json | 10 + contributors/akrsh47.json | 8 + contributors/alanoteles.json | 15 + contributors/alberto-rj.json | 14 + contributors/alekyluken.json | 9 + contributors/algacyr-melo.json | 8 + contributors/alishata128.json | 21 + contributors/allanoguis.json | 11 + contributors/allwynvarghese.json | 9 + contributors/amateurManu.json | 14 + contributors/ananfito.json | 8 + contributors/andymartinez1.json | 17 + contributors/anka-afk.json | 8 + contributors/ankit.json | 9 + contributors/anyanime.json | 9 + contributors/architxkumar.json | 39 ++ contributors/arsaylik.json | 8 + contributors/asheinT.json | 9 + contributors/asirialwis.json | 20 + contributors/aspects19.json | 21 + contributors/at-the-vr.json | 9 + contributors/badxcode.json | 15 + contributors/beckyrich.json | 13 + contributors/biroue10.json | 9 + contributors/blobmister.json | 9 + contributors/choji-alexander.json | 9 + contributors/chris-nowicki.json | 11 + contributors/chrisVCH.json | 8 + contributors/chydeepak7.json | 9 + contributors/ciprij.json | 11 + contributors/code99-ash.json | 17 + contributors/codewithjazzy.json | 8 + contributors/crow50.json | 24 + contributors/cyril-giri.json | 9 + contributors/daivydking.json | 8 + contributors/danieltott.json | 8 + contributors/darlopvil.json | 22 + contributors/david-001.json | 9 + contributors/dehanli.json | 8 + contributors/deisenhut.json | 8 + contributors/diegodemiranda.json | 15 + contributors/diegorramos84.json | 28 + contributors/divin3circle.json | 17 + contributors/doraemon2200.json | 9 + contributors/drazerd.json | 13 + contributors/droffilc1.json | 9 + contributors/dxeon.json | 8 + contributors/ebubecodes.json | 8 + contributors/edgarefigueroa.json | 14 + contributors/edwinhung.json | 14 + contributors/edwinkuruvila.json | 9 + contributors/ehsanullahhaidary.json | 11 + contributors/ekastn.json | 9 + contributors/enamcse.json | 27 + contributors/errantpianist.json | 21 + contributors/example-contributor.json | 6 + contributors/fab33150.json | 10 + contributors/favourachara07.json | 9 + contributors/franklinjpt.json | 9 + contributors/frustateduser.json | 10 + contributors/gaffarabdul.json | 9 + contributors/geoffreylgv.json | 22 + contributors/gitFerdo.json | 9 + contributors/goobric.json | 14 + contributors/hakeemyusuff.json | 10 + contributors/hediyetapan.json | 8 + contributors/hferguson.json | 10 + contributors/hokagedemehin.json | 14 + contributors/hritikyadav07.json | 9 + contributors/ht-l1.json | 14 + contributors/hurshore.json | 11 + contributors/hyosung11.json | 8 + contributors/ijayhub.json | 19 + contributors/irisxvii.json | 8 + contributors/ivngzmn.json | 19 + contributors/izazw.json | 15 + contributors/janzengo.json | 17 + contributors/jas1005.json | 9 + contributors/jayasuryard31.json | 12 + contributors/jcrosser.json | 10 + contributors/jdwilkin4.json | 21 + contributors/jiuyueshenhua.json | 9 + contributors/jmslynn.json | 9 + contributors/jurmy24.json | 12 + contributors/k1nho.json | 14 + contributors/karsterr.json | 12 + contributors/kelvinyelyen.json | 16 + contributors/kilokomuli.json | 11 + contributors/koja-amir.json | 8 + contributors/kolapowariz.json | 10 + contributors/kristiingco.json | 9 + contributors/liaxoo.json | 12 + contributors/livlaurel.json | 11 + contributors/lorenzjdr.json | 9 + contributors/luciano665.json | 24 + contributors/lukepadiachy.json | 8 + contributors/lutfiaomarr.json | 8 + contributors/macabonilas827.json | 15 + contributors/madefromjames.json | 27 + contributors/madevanni.json | 10 + contributors/manojtharindu11.json | 12 + contributors/matheus0214.json | 13 + contributors/mathncode-sid.json | 13 + contributors/max-deathray.json | 9 + contributors/mbadrawy1.json | 8 + contributors/metaltheory.json | 11 + contributors/michaelcortese.json | 10 + contributors/michaella23.json | 14 + contributors/mohanamisra.json | 23 + contributors/mrcentimetre.json | 15 + contributors/mrutunjay-kinagi.json | 15 + contributors/muou000.json | 9 + contributors/nhim-uit.json | 21 + contributors/nickaldwin.json | 10 + contributors/notavailable4u.json | 8 + contributors/observer04.json | 9 + contributors/overfero.json | 13 + contributors/pChitral.json | 21 + contributors/pal-sandeep.json | 14 + contributors/pat-fish.json | 9 + contributors/paulrwade.json | 10 + contributors/peachjelly13.json | 10 + contributors/pedaars.json | 11 + contributors/pedropalmav.json | 19 + contributors/porteristhechampion.json | 10 + contributors/prabhatisme.json | 10 + contributors/project-kieran.json | 10 + contributors/pszymaniec.json | 16 + contributors/puneet-khatri.json | 9 + contributors/pyogi27.json | 8 + contributors/rhizvo.json | 8 + contributors/robert.json | 14 + contributors/rohitkrsoni.json | 13 + contributors/rubin-r12.json | 14 + contributors/sademban.json | 9 + contributors/safaanilatasoy.json | 10 + contributors/safacade009.json | 39 ++ contributors/samgkigotho.json | 15 + contributors/samuelard7.json | 12 + contributors/sank8-2.json | 10 + contributors/sasori-morningstar.json | 9 + contributors/satyam0827.json | 10 + contributors/shafayat666.json | 18 + contributors/shampost.json | 11 + contributors/shelleymcq.json | 14 + contributors/shirenekboyd.json | 26 + contributors/shristirwt.json | 10 + contributors/shubham-singh-748.json | 9 + contributors/shubhamchasing.json | 8 + contributors/skottchen.json | 8 + contributors/smoggydesire.json | 9 + contributors/snehalk19.json | 14 + contributors/sridhar-geek.json | 8 + contributors/stephmukami.json | 9 + contributors/stop1204.json | 12 + contributors/sultanovich.json | 17 + contributors/sunggeorge.json | 19 + contributors/syke9p3.json | 12 + contributors/tech-kishore.json | 9 + contributors/tedashikode.json | 12 + contributors/tejasq.json | 6 + contributors/thititongumpun.json | 12 + contributors/tkim602.json | 12 + contributors/topSimpa.json | 8 + contributors/tpham20908.json | 12 + contributors/twister904.json | 8 + contributors/unpervertedkid.json | 8 + contributors/vaibhav3022.json | 19 + contributors/vaibhavharsoda.json | 13 + contributors/vianneyyovo.json | 10 + contributors/victor-villca.json | 14 + contributors/vivienogoun.json | 9 + contributors/voaidesr.json | 10 + contributors/wisdombe.json | 9 + contributors/wudanyang27.json | 9 + contributors/youssoph-mane.json | 6 + contributors/zairacodes.json | 15 + contributors/zh-hadi.json | 38 ++ docs/ANNOUNCEMENT.md | 77 +++ docs/DEPLOYMENT_PLAN.md | 138 +++++ docs/MIGRATION_GUIDE.md | 179 ++++++ docs/README.md | 51 ++ docs/TESTING_GUIDE.md | 255 +++++++++ docs/guides/contributor-guide.md | 114 ++++ docs/guides/testing-your-contribution.md | 111 ++++ package.json | 6 +- scripts/migrate-contributors.sh | 86 +++ scripts/preview-contribution.py | 135 +++++ scripts/test-locally.sh | 178 ++++++ scripts/validate-contributor.py | 147 +++++ scripts/verify-migration.sh | 54 ++ 335 files changed, 6243 insertions(+), 418 deletions(-) create mode 100644 .github/workflows/update-contributors.yml create mode 100644 .github/workflows/validate-contributors.yml create mode 100644 .github/workflows/validate-pr.yml create mode 100644 .github/workflows/welcome-new-contributor.yml create mode 100644 contributors/.gitkeep create mode 100644 contributors/02zeda.json create mode 100644 contributors/ATREAY.json create mode 100644 contributors/Aditya-Kumar-Sahu.json create mode 100644 contributors/Aftar-Ahmad-Sami.json create mode 100644 contributors/Ajiboso-Adeola.json create mode 100644 contributors/Akintademuyiwa24.json create mode 100644 contributors/Alejandro-Saavedra.json create mode 100644 contributors/Alex87464.json create mode 100644 contributors/Alfred-Emmanuel.json create mode 100644 contributors/Ali-Ahmed-Mohamed.json create mode 100644 contributors/Alok-Jadhao.json create mode 100644 contributors/Alz3bi.json create mode 100644 contributors/AngelMancilla.json create mode 100644 contributors/Ankit8848.json create mode 100644 contributors/Ant-Shell.json create mode 100644 contributors/ArchILLtect.json create mode 100644 contributors/Aswin-22.json create mode 100644 contributors/Axfez.json create mode 100644 contributors/Ayamigah16.json create mode 100644 contributors/AyushShuklaIIIT.json create mode 100644 contributors/BekahHW.json create mode 100644 contributors/Bradondev.json create mode 100644 contributors/BrianMunsey.json create mode 100644 contributors/BrodyWills.json create mode 100644 contributors/C-o-m-o-n.json create mode 100644 contributors/CBID2.json create mode 100644 contributors/CODINATA.json create mode 100644 contributors/ChiaBeaCode.json create mode 100644 contributors/ChinmayBagad.json create mode 100644 contributors/CodeLikeAGirl29.json create mode 100644 contributors/CynthiaWahome.json create mode 100644 contributors/DChitale.json create mode 100644 contributors/Emmarie-Ahtunan.json create mode 100644 contributors/Esaius2058.json create mode 100644 contributors/EthenThinkful.json create mode 100644 contributors/Ezzywealth.json create mode 100644 contributors/FahimJadid.json create mode 100644 contributors/Fatima-Abdirashid.json create mode 100644 contributors/Firdous2307.json create mode 100644 contributors/Franklyn883.json create mode 100644 contributors/Ghaith-Rain.json create mode 100644 contributors/Guruscod.json create mode 100644 contributors/Haimantika.json create mode 100644 contributors/Hardik-S-003.json create mode 100644 contributors/Harshdev10.json create mode 100644 contributors/Harshh18.json create mode 100644 contributors/Hellkryptonium.json create mode 100644 contributors/IM-Suryakant-Kumar.json create mode 100644 contributors/IbnuAlii.json create mode 100644 contributors/Id8987.json create mode 100644 contributors/Iqra-Issack.json create mode 100644 contributors/Izuchii.json create mode 100644 contributors/JaisonBinns.json create mode 100644 contributors/JayRKyd.json create mode 100644 contributors/JesseRWeigel.json create mode 100644 contributors/JingjieGao.json create mode 100644 contributors/JohnMwendwa.json create mode 100644 contributors/JulesRules65.json create mode 100644 contributors/Justin-WebDev.json create mode 100644 contributors/Kaanan2000.json create mode 100644 contributors/Kamari93.json create mode 100644 contributors/Kaz-Smino.json create mode 100644 contributors/Ken-Musau.json create mode 100644 contributors/Lmdingi.json create mode 100644 contributors/Lor1138.json create mode 100644 contributors/Luca1905.json create mode 100644 contributors/LuisCFunes.json create mode 100644 contributors/Lymah123.json create mode 100644 contributors/MadAvidCoder.json create mode 100644 contributors/ManuelaFlores.json create mode 100644 contributors/MarcellaHarr.json create mode 100644 contributors/MayankChandratre1.json create mode 100644 contributors/MehediMubin.json create mode 100644 contributors/Metratrj.json create mode 100644 contributors/Mi1king.json create mode 100644 contributors/MohamedAliJmal.json create mode 100644 contributors/Msrimpson.json create mode 100644 contributors/Mugabe000.json create mode 100644 contributors/Muniir1.json create mode 100644 contributors/Muskan-Seth03.json create mode 100644 contributors/Muyixone.json create mode 100644 contributors/Muzammil-cyber.json create mode 100644 contributors/Nabinbista12.json create mode 100644 contributors/Neerajrawat123.json create mode 100644 contributors/NeverGray.json create mode 100644 contributors/Obasoro.json create mode 100644 contributors/OluwabukolaU.json create mode 100644 contributors/Pondy007.json create mode 100644 contributors/QUxPTA.json create mode 100644 contributors/Quartel.json create mode 100644 contributors/README.md create mode 100644 contributors/RafaelJohn9.json create mode 100644 contributors/RayX81194.json create mode 100644 contributors/Rijan-Joshi.json create mode 100644 contributors/Sadeedpv.json create mode 100644 contributors/SamarMst.json create mode 100644 contributors/Satoshi-Sh.json create mode 100644 contributors/Shin1ma.json create mode 100644 contributors/SimonGideon.json create mode 100644 contributors/SkipPharaoh.json create mode 100644 contributors/SnowyCrest.json create mode 100644 contributors/Solenessa.json create mode 100644 contributors/SoufianeJm.json create mode 100644 contributors/Spcxx.json create mode 100644 contributors/Suei43.json create mode 100644 contributors/Suldana.json create mode 100644 contributors/Sunny-unik.json create mode 100644 contributors/SusanGithaigaN.json create mode 100644 contributors/SushiJ.json create mode 100644 contributors/Tamale1.json create mode 100644 contributors/TanishqV5.json create mode 100644 contributors/Tawan-B.json create mode 100644 contributors/Teemamin.json create mode 100644 contributors/TejsinghDhaosriya.json create mode 100644 contributors/TheOphige.json create mode 100644 contributors/TomasDarquier.json create mode 100644 contributors/ToniBirat7.json create mode 100644 contributors/ToobaJamal.json create mode 100644 contributors/Ufidtech.json create mode 100644 contributors/ValLee4.json create mode 100644 contributors/ValarieOyieke.json create mode 100644 contributors/Vamsi-344.json create mode 100644 contributors/Vikingu-del.json create mode 100644 contributors/VirginieLemaire.json create mode 100644 contributors/WassCodeur.json create mode 100644 contributors/Woytsekj.json create mode 100644 contributors/WybsonSantana.json create mode 100644 contributors/YoungGunner14.json create mode 100644 contributors/ZeeshanMukhtar1.json create mode 100644 contributors/Zier0Code.json create mode 100644 contributors/acskii.json create mode 100644 contributors/adaniel105.json create mode 100644 contributors/adiati98.json create mode 100644 contributors/adiazt01.json create mode 100644 contributors/aerg04.json create mode 100644 contributors/akrsh47.json create mode 100644 contributors/alanoteles.json create mode 100644 contributors/alberto-rj.json create mode 100644 contributors/alekyluken.json create mode 100644 contributors/algacyr-melo.json create mode 100644 contributors/alishata128.json create mode 100644 contributors/allanoguis.json create mode 100644 contributors/allwynvarghese.json create mode 100644 contributors/amateurManu.json create mode 100644 contributors/ananfito.json create mode 100644 contributors/andymartinez1.json create mode 100644 contributors/anka-afk.json create mode 100644 contributors/ankit.json create mode 100644 contributors/anyanime.json create mode 100644 contributors/architxkumar.json create mode 100644 contributors/arsaylik.json create mode 100644 contributors/asheinT.json create mode 100644 contributors/asirialwis.json create mode 100644 contributors/aspects19.json create mode 100644 contributors/at-the-vr.json create mode 100644 contributors/badxcode.json create mode 100644 contributors/beckyrich.json create mode 100644 contributors/biroue10.json create mode 100644 contributors/blobmister.json create mode 100644 contributors/choji-alexander.json create mode 100644 contributors/chris-nowicki.json create mode 100644 contributors/chrisVCH.json create mode 100644 contributors/chydeepak7.json create mode 100644 contributors/ciprij.json create mode 100644 contributors/code99-ash.json create mode 100644 contributors/codewithjazzy.json create mode 100644 contributors/crow50.json create mode 100644 contributors/cyril-giri.json create mode 100644 contributors/daivydking.json create mode 100644 contributors/danieltott.json create mode 100644 contributors/darlopvil.json create mode 100644 contributors/david-001.json create mode 100644 contributors/dehanli.json create mode 100644 contributors/deisenhut.json create mode 100644 contributors/diegodemiranda.json create mode 100644 contributors/diegorramos84.json create mode 100644 contributors/divin3circle.json create mode 100644 contributors/doraemon2200.json create mode 100644 contributors/drazerd.json create mode 100644 contributors/droffilc1.json create mode 100644 contributors/dxeon.json create mode 100644 contributors/ebubecodes.json create mode 100644 contributors/edgarefigueroa.json create mode 100644 contributors/edwinhung.json create mode 100644 contributors/edwinkuruvila.json create mode 100644 contributors/ehsanullahhaidary.json create mode 100644 contributors/ekastn.json create mode 100644 contributors/enamcse.json create mode 100644 contributors/errantpianist.json create mode 100644 contributors/example-contributor.json create mode 100644 contributors/fab33150.json create mode 100644 contributors/favourachara07.json create mode 100644 contributors/franklinjpt.json create mode 100644 contributors/frustateduser.json create mode 100644 contributors/gaffarabdul.json create mode 100644 contributors/geoffreylgv.json create mode 100644 contributors/gitFerdo.json create mode 100644 contributors/goobric.json create mode 100644 contributors/hakeemyusuff.json create mode 100644 contributors/hediyetapan.json create mode 100644 contributors/hferguson.json create mode 100644 contributors/hokagedemehin.json create mode 100644 contributors/hritikyadav07.json create mode 100644 contributors/ht-l1.json create mode 100644 contributors/hurshore.json create mode 100644 contributors/hyosung11.json create mode 100644 contributors/ijayhub.json create mode 100644 contributors/irisxvii.json create mode 100644 contributors/ivngzmn.json create mode 100644 contributors/izazw.json create mode 100644 contributors/janzengo.json create mode 100644 contributors/jas1005.json create mode 100644 contributors/jayasuryard31.json create mode 100644 contributors/jcrosser.json create mode 100644 contributors/jdwilkin4.json create mode 100644 contributors/jiuyueshenhua.json create mode 100644 contributors/jmslynn.json create mode 100644 contributors/jurmy24.json create mode 100644 contributors/k1nho.json create mode 100644 contributors/karsterr.json create mode 100644 contributors/kelvinyelyen.json create mode 100644 contributors/kilokomuli.json create mode 100644 contributors/koja-amir.json create mode 100644 contributors/kolapowariz.json create mode 100644 contributors/kristiingco.json create mode 100644 contributors/liaxoo.json create mode 100644 contributors/livlaurel.json create mode 100644 contributors/lorenzjdr.json create mode 100644 contributors/luciano665.json create mode 100644 contributors/lukepadiachy.json create mode 100644 contributors/lutfiaomarr.json create mode 100644 contributors/macabonilas827.json create mode 100644 contributors/madefromjames.json create mode 100644 contributors/madevanni.json create mode 100644 contributors/manojtharindu11.json create mode 100644 contributors/matheus0214.json create mode 100644 contributors/mathncode-sid.json create mode 100644 contributors/max-deathray.json create mode 100644 contributors/mbadrawy1.json create mode 100644 contributors/metaltheory.json create mode 100644 contributors/michaelcortese.json create mode 100644 contributors/michaella23.json create mode 100644 contributors/mohanamisra.json create mode 100644 contributors/mrcentimetre.json create mode 100644 contributors/mrutunjay-kinagi.json create mode 100644 contributors/muou000.json create mode 100644 contributors/nhim-uit.json create mode 100644 contributors/nickaldwin.json create mode 100644 contributors/notavailable4u.json create mode 100644 contributors/observer04.json create mode 100644 contributors/overfero.json create mode 100644 contributors/pChitral.json create mode 100644 contributors/pal-sandeep.json create mode 100644 contributors/pat-fish.json create mode 100644 contributors/paulrwade.json create mode 100644 contributors/peachjelly13.json create mode 100644 contributors/pedaars.json create mode 100644 contributors/pedropalmav.json create mode 100644 contributors/porteristhechampion.json create mode 100644 contributors/prabhatisme.json create mode 100644 contributors/project-kieran.json create mode 100644 contributors/pszymaniec.json create mode 100644 contributors/puneet-khatri.json create mode 100644 contributors/pyogi27.json create mode 100644 contributors/rhizvo.json create mode 100644 contributors/robert.json create mode 100644 contributors/rohitkrsoni.json create mode 100644 contributors/rubin-r12.json create mode 100644 contributors/sademban.json create mode 100644 contributors/safaanilatasoy.json create mode 100644 contributors/safacade009.json create mode 100644 contributors/samgkigotho.json create mode 100644 contributors/samuelard7.json create mode 100644 contributors/sank8-2.json create mode 100644 contributors/sasori-morningstar.json create mode 100644 contributors/satyam0827.json create mode 100644 contributors/shafayat666.json create mode 100644 contributors/shampost.json create mode 100644 contributors/shelleymcq.json create mode 100644 contributors/shirenekboyd.json create mode 100644 contributors/shristirwt.json create mode 100644 contributors/shubham-singh-748.json create mode 100644 contributors/shubhamchasing.json create mode 100644 contributors/skottchen.json create mode 100644 contributors/smoggydesire.json create mode 100644 contributors/snehalk19.json create mode 100644 contributors/sridhar-geek.json create mode 100644 contributors/stephmukami.json create mode 100644 contributors/stop1204.json create mode 100644 contributors/sultanovich.json create mode 100644 contributors/sunggeorge.json create mode 100644 contributors/syke9p3.json create mode 100644 contributors/tech-kishore.json create mode 100644 contributors/tedashikode.json create mode 100644 contributors/tejasq.json create mode 100644 contributors/thititongumpun.json create mode 100644 contributors/tkim602.json create mode 100644 contributors/topSimpa.json create mode 100644 contributors/tpham20908.json create mode 100644 contributors/twister904.json create mode 100644 contributors/unpervertedkid.json create mode 100644 contributors/vaibhav3022.json create mode 100644 contributors/vaibhavharsoda.json create mode 100644 contributors/vianneyyovo.json create mode 100644 contributors/victor-villca.json create mode 100644 contributors/vivienogoun.json create mode 100644 contributors/voaidesr.json create mode 100644 contributors/wisdombe.json create mode 100644 contributors/wudanyang27.json create mode 100644 contributors/youssoph-mane.json create mode 100644 contributors/zairacodes.json create mode 100644 contributors/zh-hadi.json create mode 100644 docs/ANNOUNCEMENT.md create mode 100644 docs/DEPLOYMENT_PLAN.md create mode 100644 docs/MIGRATION_GUIDE.md create mode 100644 docs/README.md create mode 100644 docs/TESTING_GUIDE.md create mode 100644 docs/guides/contributor-guide.md create mode 100644 docs/guides/testing-your-contribution.md create mode 100755 scripts/migrate-contributors.sh create mode 100755 scripts/preview-contribution.py create mode 100755 scripts/test-locally.sh create mode 100755 scripts/validate-contributor.py create mode 100755 scripts/verify-migration.sh diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 1c2bf2f..cafef70 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,48 +1,59 @@ - +## Type of Contribution -## Description + - +- [ ] ๐ŸŽ‰ **Adding myself as a new contributor** (following the intro course) +- [ ] ๐Ÿ› **Bug fix** +- [ ] โœจ **New feature** +- [ ] ๐Ÿ“ **Documentation update** +- [ ] ๐Ÿ”ง **Other maintenance/improvement** -## What type of PR is this? (check all applicable) +--- -- [ ] ๐Ÿค Add a contributor -- [ ] ๐Ÿ“ Documentation Update +## For New Contributors (Adding Yourself to Guestbook) -## Related Issues + - +### About Me +**Name:** +**Location (optional):** +**What I'm learning:** +**Fun fact:** -## Contributors Checklist +--- -### I've read through the [Getting Started](https://intro.opensauced.pizza/#/intro-to-oss/how-to-contribute-to-open-source?id=getting-started) section +## For Other Contributions -- [ ] โœ… Yes -- [ ] โŒ Not yet + -### Have you run `npm run contributors:generate` to generate your profile and the badge on the README? +### Description + -- [ ] โœ… Yes -- [ ] โŒ No +### Changes Made + +- +- +- -## Added to documentation? +### Screenshots (if applicable) + -- [ ] ๐Ÿ“œ README.md -- [ ] ๐Ÿ™… no documentation needed +### Testing +- [ ] I have tested these changes locally +- [ ] I have reviewed my own code +- [ ] I have added/updated documentation if needed -## Screenshot (Required for PR Review) +--- - +## Additional Notes + ## [optional] What GIF best describes this PR or how it makes you feel? diff --git a/.github/workflows/intro_course_contributor.yml b/.github/workflows/intro_course_contributor.yml index b24e572..b5eb38b 100644 --- a/.github/workflows/intro_course_contributor.yml +++ b/.github/workflows/intro_course_contributor.yml @@ -16,5 +16,5 @@ jobs: - name: Post comment for course contributors if: contains(github.event.pull_request.title, 'as a contributor') run: | - PR_COMMENT="Congratulations on completing the How to Contribute to Open Source chapter of the Intro to Open Source Course with your contribution to this repository, @${{ github.actor }}! You're almost to the end of the course. Create a [highlight](https://app.opensauced.pizza/feed) of your contribution to our guestbook using the instructions in the [next chapter](https://github.com/open-sauced/intro/blob/main/docs/intro-to-oss/the-secret-sauce.md) and share it with us!" + PR_COMMENT="Congratulations on completing the How to Contribute to Open Source chapter of the Intro to Open Source Course with your contribution to this repository, @${{ github.actor }}! You're almost to the end of the course." curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -X POST -d "{\"body\":\"$PR_COMMENT\"}" "https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml new file mode 100644 index 0000000..94b77ad --- /dev/null +++ b/.github/workflows/update-contributors.yml @@ -0,0 +1,141 @@ +name: Update Contributors + +on: + push: + branches: [main] + paths: ['contributors/*.json'] + + # Allow manual triggering for maintenance + workflow_dispatch: + +permissions: + contents: write + pull-requests: read + +jobs: + update-contributors: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + + - name: Install dependencies + run: | + npm install -g all-contributors-cli + + - name: Backup current contributors + run: | + cp .all-contributorsrc .all-contributorsrc.backup || echo "No existing config found" + + - name: Reset all-contributors config + run: | + # Create fresh config + cat > .all-contributorsrc << 'EOF' + { + "projectName": "guestbook", + "projectOwner": "OpenSource-Community", + "repoType": "github", + "repoHost": "https://github.com", + "files": ["README.md"], + "imageSize": 100, + "commit": false, + "commitConvention": "angular", + "contributors": [] + } + EOF + + - name: Process contributor files + run: | + echo "Processing contributor files..." + + # Check if contributors directory exists and has files + if [ ! -d "contributors" ] || [ -z "$(ls -A contributors/*.json 2>/dev/null)" ]; then + echo "No contributor files found" + exit 0 + fi + + # Process each JSON file + for file in contributors/*.json; do + if [ -f "$file" ]; then + filename=$(basename "$file") + + # Skip example and template files + if [[ "$filename" == "example-contributor.json" ]] || [[ "$filename" == ".gitkeep" ]]; then + echo "Skipping template file: $filename" + continue + fi + + echo "Processing $file" + + # Validate JSON (basic check) + if ! python3 -c "import json; json.load(open('$file'))" 2>/dev/null; then + echo "Error: Invalid JSON in $file" + continue + fi + + # Extract data using Python since jq might not be available + username=$(basename "$file" .json) + name=$(python3 -c "import json; data=json.load(open('$file')); print(data.get('name', ''))") + github_username=$(python3 -c "import json; data=json.load(open('$file')); print(data.get('github', ''))") + profile=$(python3 -c "import json; data=json.load(open('$file')); print(data.get('profile', ''))") + contributions=$(python3 -c "import json; data=json.load(open('$file')); print(','.join(data.get('contributions', [])))") + + # Validate required fields + if [ -z "$name" ] || [ -z "$github_username" ] || [ -z "$contributions" ]; then + echo "Error: Missing required fields in $file" + continue + fi + + # Add contributor + echo "Adding contributor: $name (@$github_username)" + + if [ -n "$profile" ] && [ "$profile" != "null" ] && [ "$profile" != "" ]; then + npx all-contributors add "$github_username" "$contributions" --url "$profile" --name "$name" + else + npx all-contributors add "$github_username" "$contributions" --name "$name" + fi + fi + done + + - name: Generate contributors section + run: | + npx all-contributors generate + + - name: Check for changes + id: changes + run: | + if [ -n "$(git status --porcelain)" ]; then + echo "changes=true" >> $GITHUB_OUTPUT + else + echo "changes=false" >> $GITHUB_OUTPUT + fi + + - name: Commit and push changes + if: steps.changes.outputs.changes == 'true' + run: | + git config --local user.email "action@github.com" + git config --local user.name "Contributors Bot" + + git add . + git commit -m "chore: update contributors list + + Auto-generated from contributors/*.json files + + [skip ci]" + git push + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Success notification + if: steps.changes.outputs.changes == 'true' + run: | + echo "โœ… Contributors list updated successfully!" + echo "Changes committed and pushed to main branch." \ No newline at end of file diff --git a/.github/workflows/validate-contributors.yml b/.github/workflows/validate-contributors.yml new file mode 100644 index 0000000..2409a1d --- /dev/null +++ b/.github/workflows/validate-contributors.yml @@ -0,0 +1,52 @@ +name: Validate Contributors + +on: + pull_request: + paths: + - 'contributors/*.json' + push: + branches: [main] + paths: + - 'contributors/*.json' + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + - name: Validate contributor files + run: | + python3 scripts/validate-contributor.py + + - name: Check for duplicate contributors + run: | + # Check for duplicate GitHub usernames + duplicates=$(find contributors/ -name "*.json" -exec basename {} .json \; | sort | uniq -d) + if [ -n "$duplicates" ]; then + echo "โŒ Duplicate contributor files found:" + echo "$duplicates" + exit 1 + else + echo "โœ… No duplicate contributors found" + fi + + - name: Validate JSON syntax + run: | + echo "๐Ÿ” Validating JSON syntax..." + for file in contributors/*.json; do + if [ -f "$file" ]; then + echo "Checking $file..." + python3 -c "import json; json.load(open('$file'))" || { + echo "โŒ Invalid JSON in $file" + exit 1 + } + fi + done + echo "โœ… All JSON files have valid syntax" \ No newline at end of file diff --git a/.github/workflows/validate-pr.yml b/.github/workflows/validate-pr.yml new file mode 100644 index 0000000..9957b69 --- /dev/null +++ b/.github/workflows/validate-pr.yml @@ -0,0 +1,121 @@ +name: Validate Pull Request + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + validate-contributor-pr: + if: contains(github.event.pull_request.title, 'contributor') || contains(github.event.pull_request.title, 'Add') + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v39 + with: + files: contributors/*.json + + - name: Validate contributor submission + if: steps.changed-files.outputs.any_changed == 'true' + run: | + echo "๐Ÿ” Validating contributor submission..." + + # Get the list of changed files + changed_files="${{ steps.changed-files.outputs.all_changed_files }}" + + echo "Changed files: $changed_files" + + # Count number of changed files + file_count=$(echo "$changed_files" | wc -w) + + if [ "$file_count" -gt 1 ]; then + echo "โŒ ERROR: Please only add ONE contributor file per PR" + echo " You've changed $file_count files: $changed_files" + echo " Create separate PRs for each contributor." + exit 1 + fi + + # Validate the single file + for file in $changed_files; do + echo "Validating $file..." + + # Check if it's a JSON file in contributors directory + if [[ ! "$file" =~ ^contributors/[^/]+\.json$ ]]; then + echo "โŒ ERROR: Invalid file location. Must be contributors/username.json" + exit 1 + fi + + # Extract filename without path and extension + filename=$(basename "$file" .json) + + # Validate JSON structure + python3 -c " +import json +import sys + +try: + with open('$file', 'r') as f: + data = json.load(f) + + required_fields = ['name', 'github', 'contributions'] + missing_fields = [field for field in required_fields if field not in data or not data[field]] + + if missing_fields: + print(f'โŒ ERROR: Missing required fields: {missing_fields}') + sys.exit(1) + + # Check if filename matches github username + if data['github'] != '$filename': + print(f'โŒ ERROR: Filename must match GitHub username') + print(f' File: $filename.json') + print(f' GitHub username in file: {data[\"github\"]}') + print(f' Should be: {data[\"github\"]}.json') + sys.exit(1) + + print('โœ… Contributor file is valid!') + +except json.JSONDecodeError as e: + print(f'โŒ ERROR: Invalid JSON format: {e}') + sys.exit(1) +except Exception as e: + print(f'โŒ ERROR: {e}') + sys.exit(1) +" || exit 1 + done + + echo "โœ… All validations passed!" + + - name: Welcome comment for new contributors + if: steps.changed-files.outputs.any_changed == 'true' + uses: actions/github-script@v7 + with: + script: | + const changedFiles = '${{ steps.changed-files.outputs.all_changed_files }}'; + + if (changedFiles.trim()) { + const comment = `๐ŸŽ‰ **Welcome to the guestbook!** + + Thank you for contributing! Your submission looks good and follows the new conflict-free process. + + Once this PR is merged: + - โœ… You'll be automatically added to the contributors list in the README + - ๐ŸŽ“ You can continue with the next step in the [Intro to Open Source course](https://opensauced.pizza/learn/intro-to-oss/) + - ๐ŸŒŸ Consider creating a [highlight](https://app.opensauced.pizza/feed) of your contribution! + + **What happens next?** + - A maintainer will review your PR + - After merge, a GitHub Action will automatically update the README + - You'll see your profile appear in the contributors section! + + Thanks for being part of the open source community! ๐Ÿš€`; + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: comment + }); + } \ No newline at end of file diff --git a/.github/workflows/welcome-new-contributor.yml b/.github/workflows/welcome-new-contributor.yml new file mode 100644 index 0000000..6a8bf9e --- /dev/null +++ b/.github/workflows/welcome-new-contributor.yml @@ -0,0 +1,52 @@ +name: Welcome New Contributors + +on: + pull_request_target: + types: [closed] + paths: + - 'contributors/*.json' + +permissions: + pull-requests: write + issues: write + +jobs: + welcome: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - name: Welcome new contributor + uses: actions/github-script@v7 + with: + script: | + // Check if this is a contributor addition PR + const prTitle = context.payload.pull_request.title.toLowerCase(); + const isContributorPR = prTitle.includes('contributor') || prTitle.includes('add') || prTitle.includes('guestbook'); + + if (isContributorPR) { + const welcomeMessage = `๐ŸŽ‰ **Congratulations @${context.payload.pull_request.user.login}!** + + Your contribution has been successfully merged and you're now part of our contributors list! + + **What just happened:** + โœ… Your contributor JSON file was processed + โœ… The README has been automatically updated with your information + โœ… You're now officially a contributor to this open source project! + + **Next steps from the Intro to Open Source course:** + ๐Ÿ• Check out the [pizza-verse](https://github.com/OpenSource-Communities/pizza-verse) repository for more contributions! + + **Share your success:** + - Post about your first open source contribution on socials + - Share in the [OpenSauced Discord](https://discord.gg/U2peSNf23P) + - Tell your friends about the course! + + Welcome to the open source community! ๐Ÿš€`; + + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: welcomeMessage + }); + } \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5370378..47b8fb8 100644 --- a/.gitignore +++ b/.gitignore @@ -245,4 +245,5 @@ sketch .history .ionide -# End of https://www.toptal.com/developers/gitignore/api/node,macos,next,typescript,react,visualstudiocode,nextjs,solidjs,qwik,mitosis + + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 66790cb..8d3e1a3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,13 @@ # Contributing Guidelines -This repository is part of the [Intro to Open Source course](https://opensauced.pizza/learn/intro-to-oss/). We recommend you to take and complete the course before you contribute to this repository. +This repository is part of the [Intro to Open Source course](https://opensauced.pizza/learn/intro-to-oss/). We recommend you take and complete the course before you contribute to this repository. Contributions are always welcome, no matter how large or small. Before you begin, please read our [Code of Conduct](https://github.com/OpenSource-Communities/.github/blob/main/CODE_OF_CONDUCT.md) and follow the directions below: +## ๐ŸŽ‰ Adding Yourself as a Contributor + +๐Ÿ“– To add yourself as a contributor to the guestbook, please **see [docs/guides/contributor-guide.md](docs/guides/contributor-guide.md) for detailed instructions and examples** + ## Recommended Communication Style 1. Always leave screenshots for visual changes. @@ -20,4 +24,12 @@ In case you get stuck, feel free to ask for help in the [discussion](https://git ## Getting Started -Please follow the [Let's Get Practical](https://opensauced.pizza/learn/intro-to-oss/how-to-contribute-to-open-source#lets-get-practical) section of the [Intro to Open Source course](https://opensauced.pizza/learn/intro-to-oss/) to add yourself to the guestbook. +Please follow the updated instructions in [docs/guides/contributor-guide.md](docs/guides/contributor-guide.md) to add yourself to the guestbook. + +## Other Types of Contributions + +For contributions other than adding yourself to the guestbook, please follow the standard GitHub workflow: +1. Fork the repository +2. Create a new branch +3. Make your changes +4. Submit a pull request diff --git a/README.md b/README.md index ec0320e..9c0c55a 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,37 @@ This guestbook is a place for people who have taken the [Intro to Open Source co ## Getting Started -For complete instructions on how to add yourself to this guestbook, please head to the "[Let's Get Practical](https://opensauced.pizza/learn/intro-to-oss/how-to-contribute-to-open-source#lets-get-practical)" section in the Intro to Open Source course. +**๐ŸŽ‰ New simplified process - no more merge conflicts!** -## Resolving Merge Conflicts +Instead of editing this README directly, you now add yourself by creating a single JSON file. This prevents merge conflicts when multiple people contribute simultaneously. -If you encounter merge conflicts while contributing to this repository, read the Intro to Open Source course's "[Merge Conflicts in the Guestbook Repository](https://opensauced.pizza/learn/intro-to-oss/how-to-contribute-to-open-source#merge-conflicts-in-the-guestbook-repository)" section. +### Quick Start +1. Go to the [`contributors/`](contributors/) directory +2. Create a file named `your-github-username.json` +3. Fill it with your information (see template below) +4. Submit your PR with just that one file! + +### Template +```json +{ + "name": "Your Full Name", + "github": "your-github-username", + "profile": "https://your-website.com", + "contributions": ["code", "doc", "ideas"] +} +``` + +๐Ÿ“– **For detailed instructions, see: [docs/guides/contributor-guide.md](docs/guides/contributor-guide.md)** + +> **Note**: The contributors table below is automatically updated when your PR is merged. No need to edit it manually! +> +> ๐Ÿงช **Want to test if it worked?** See: [docs/guides/testing-your-contribution.md](docs/guides/testing-your-contribution.md) + +## No More Merge Conflicts! + +๐ŸŽ‰ **Good news!** The new contributor system eliminates merge conflicts entirely. Each contributor creates their own unique file, so multiple people can contribute simultaneously without conflicts. + +If you still encounter issues, check out the [Migration Guide](docs/MIGRATION_GUIDE.md) or ask for help in [GitHub Discussions](../../discussions). ## What's Next? @@ -39,419 +65,157 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Tejas Kumar
Tejas Kumar

- pszymaniec
pszymaniec

๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ’ก ๐Ÿ”ฌ ๐ŸŒ โœ… ๐Ÿ› - BekahHW
BekahHW

๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿค” ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ“ข โš ๏ธ โœ… ๐Ÿ“น - ValarieOyieke
ValarieOyieke

๐Ÿ› ๐Ÿ’ป ๐Ÿ’ก ๐Ÿ‘€ ๐Ÿ““ - Shirene Kadkhodai Boyd
Shirene Kadkhodai Boyd

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿค” ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”Œ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐Ÿ““ - Shelley McHardy
Shelley McHardy

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ“– ๐Ÿ“‹ ๐Ÿง‘โ€๐Ÿซ ๐Ÿ‘€ โœ… - jmslynn
jmslynn

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ป + pszymaniec
pszymaniec

๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ’ก ๐Ÿ”ฌ ๐ŸŒ โœ… ๐Ÿ› + BekahHW
BekahHW

๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿค” ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ“ข โš ๏ธ โœ… ๐Ÿ“น + ValarieOyieke
ValarieOyieke

๐Ÿ› ๐Ÿ’ป ๐Ÿ’ก ๐Ÿ‘€ ๐Ÿ““ + Shirene Kadkhodai Boyd
Shirene Kadkhodai Boyd

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿค” ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”Œ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐Ÿ““ + Shelley McHardy
Shelley McHardy

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ“– ๐Ÿ“‹ ๐Ÿง‘โ€๐Ÿซ ๐Ÿ‘€ โœ… + jmslynn
jmslynn

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ป - Ayu Adiati
Ayu Adiati

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ’ก ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ข ๐ŸŒ + Ayu Adiati
Ayu Adiati

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ’ก ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ข ๐ŸŒ Clifford Mapesa
Clifford Mapesa

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ โœ… - Edgar Figueroa
Edgar Figueroa

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ”ฌ ๐Ÿ›ก๏ธ โš ๏ธ ๐ŸŒ - Mark Anel Cabonilas
Mark Anel Cabonilas

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿค” ๐Ÿ”ง - Dan Eisenhut
Dan Eisenhut

๐Ÿ’ป - Jay Knowles
Jay Knowles

๐Ÿ“ ๐Ÿ’ป - BIROUE ISAAC
BIROUE ISAAC

๐Ÿ’ป ๐ŸŒ + Edgar Figueroa
Edgar Figueroa

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ”ฌ ๐Ÿ›ก๏ธ โš ๏ธ ๐ŸŒ + Mark Anel Cabonilas
Mark Anel Cabonilas

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿค” ๐Ÿ”ง + Dan Eisenhut
Dan Eisenhut

๐Ÿ’ป + Jay Knowles
Jay Knowles

๐Ÿ“ ๐Ÿ’ป + BIROUE ISAAC
BIROUE ISAAC

๐Ÿ’ป ๐ŸŒ - Alarezomo Osamuyi
Alarezomo Osamuyi

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ”Š ๐Ÿง‘โ€๐Ÿซ ๐Ÿ““ ๐Ÿ’ฌ โš ๏ธ ๐ŸŒ ๐Ÿ“ข - Sushant Sharma
Sushant Sharma

๐Ÿ“– - Ali Shata
Ali Shata

๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿค” ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ“ข โœ… - Anthony Nanfito
Anthony Nanfito

๐Ÿ’ป - Kin NG
Kin NG

๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐ŸŽจ ๐Ÿ“– ๐Ÿš‡ ๐Ÿ‘€ - zh-hadi
zh-hadi

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿ’ต ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ ๐Ÿ“น - Santiago Montoya Rendรณn
Santiago Montoya Rendรณn

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿšง + Alarezomo Osamuyi
Alarezomo Osamuyi

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ”Š ๐Ÿง‘โ€๐Ÿซ ๐Ÿ““ ๐Ÿ’ฌ โš ๏ธ ๐ŸŒ ๐Ÿ“ข + Sushant Sharma
Sushant Sharma

๐Ÿ“– + Ali Shata
Ali Shata

๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿค” ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ“ข โœ… + Anthony Nanfito
Anthony Nanfito

๐Ÿ’ป + Kin NG
Kin NG

๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐ŸŽจ ๐Ÿ“– ๐Ÿš‡ ๐Ÿ‘€ + zh-hadi
zh-hadi

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿ’ต ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ ๐Ÿ“น + Santiago Montoya Rendรณn
Santiago Montoya Rendรณn

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿšง - Atreay  Kukanur
Atreay Kukanur

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ–‹ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿค” ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ““ + Atreay  Kukanur
Atreay Kukanur

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ–‹ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿค” ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ““ Ms. Suldana
Ms. Suldana

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ - Prabhat Bhagel
Prabhat Bhagel

๐Ÿ”Š ๐Ÿ’ป ๐ŸŽจ - Kelvin Yelyen
Kelvin Yelyen

๐Ÿ’ป ๐Ÿ–‹ ๐ŸŽจ ๐Ÿ› ๐Ÿ“– ๐Ÿค” ๐Ÿ“† ๐Ÿ”ฌ โš ๏ธ - Fatima-Abdirashid
Fatima-Abdirashid

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ ๐Ÿ“น + Prabhat Bhagel
Prabhat Bhagel

๐Ÿ”Š ๐Ÿ’ป ๐ŸŽจ + Kelvin Yelyen
Kelvin Yelyen

๐Ÿ’ป ๐Ÿ–‹ ๐ŸŽจ ๐Ÿ› ๐Ÿ“– ๐Ÿค” ๐Ÿ“† ๐Ÿ”ฌ โš ๏ธ + Fatima-Abdirashid
Fatima-Abdirashid

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ ๐Ÿ“น Iqra-Issack
Iqra-Issack

๐Ÿš‡ ๐Ÿšง muniir1
muniir1

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ - Anyanime Benson
Anyanime Benson

๐Ÿ’ป ๐Ÿ“– + Anyanime Benson
Anyanime Benson

๐Ÿ’ป ๐Ÿ“– Mohamed Ali Nor
Mohamed Ali Nor

๐Ÿ“ฃ - Folarin Raphael
Folarin Raphael

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ“– ๐Ÿšง ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ‘€ โš ๏ธ ๐ŸŒ ๐Ÿ““ + Folarin Raphael
Folarin Raphael

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ“– ๐Ÿšง ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ‘€ โš ๏ธ ๐ŸŒ ๐Ÿ““ lutfiaomarr
lutfiaomarr

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ - Ali-Ahmed-Mohamed
Ali-Ahmed-Mohamed

๐Ÿ’ป - Fabrice Innocent
Fabrice Innocent

๐Ÿ“ ๐Ÿ’ป ๐Ÿ‘€ - Becky Richardson
Becky Richardson

๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐ŸŽจ ๐Ÿ“– + Ali-Ahmed-Mohamed
Ali-Ahmed-Mohamed

๐Ÿ’ป + Fabrice Innocent
Fabrice Innocent

๐Ÿ“ ๐Ÿ’ป ๐Ÿ‘€ + Becky Richardson
Becky Richardson

๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐ŸŽจ ๐Ÿ“– - Chris Nowicki
Chris Nowicki

๐Ÿ’ป ๐Ÿ“ ๐Ÿ“– โœ… - Frank Alimimian
Frank Alimimian

๐Ÿ“ ๐Ÿ’ป ๐Ÿ“– ๐Ÿ”ฌ - Dan Ott
Dan Ott

๐Ÿ’ป - Samgkigotho
Samgkigotho

๐Ÿ“ ๐Ÿ› ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” - Anthony Shellman
Anthony Shellman

๐Ÿ’ป ๐Ÿ“– ๐Ÿ”ฌ - Alano Teles
Alano Teles

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ”ฌ ๐ŸŒ - Hannah Lin
Hannah Lin

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿค” ๐Ÿš‡ ๐Ÿšง + Chris Nowicki
Chris Nowicki

๐Ÿ’ป ๐Ÿ“ ๐Ÿ“– โœ… + Frank Alimimian
Frank Alimimian

๐Ÿ“ ๐Ÿ’ป ๐Ÿ“– ๐Ÿ”ฌ + Dan Ott
Dan Ott

๐Ÿ’ป + Samgkigotho
Samgkigotho

๐Ÿ“ ๐Ÿ› ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” + Anthony Shellman
Anthony Shellman

๐Ÿ’ป ๐Ÿ“– ๐Ÿ”ฌ + Alano Teles
Alano Teles

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ”ฌ ๐ŸŒ + Hannah Lin
Hannah Lin

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿค” ๐Ÿš‡ ๐Ÿšง - Ethen Roth
Ethen Roth

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿค” ๐Ÿ‘€ - koder_
koder_

๐Ÿ’ป ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿ”ฌ - Ikhlas
Ikhlas

๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐ŸŽจ ๐Ÿค” ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ““ ๐Ÿ“น - Christine Belzie
Christine Belzie

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ‘€ โœ… ๐Ÿ’ก ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ - Diego Ramos
Diego Ramos

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ‘€ โœ… ๐Ÿ’ก ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ - thititongumpun
thititongumpun

๐Ÿ› ๐Ÿ’ป ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿš‡ - Jayasurya R D
Jayasurya R D

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿค” ๐ŸŽจ ๐Ÿ‘€ + Ethen Roth
Ethen Roth

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿค” ๐Ÿ‘€ + koder_
koder_

๐Ÿ’ป ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿ”ฌ + Ikhlas
Ikhlas

๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐ŸŽจ ๐Ÿค” ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ““ ๐Ÿ“น + Christine Belzie
Christine Belzie

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ‘€ โœ… ๐Ÿ’ก ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ + Diego Ramos
Diego Ramos

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ‘€ โœ… ๐Ÿ’ก ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ + thititongumpun
thititongumpun

๐Ÿ› ๐Ÿ’ป ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿš‡ + Jayasurya R D
Jayasurya R D

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿค” ๐ŸŽจ ๐Ÿ‘€ - Obasoro
Obasoro

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿš‡ ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ โš ๏ธ ๐Ÿ”ง ๐Ÿ““ - Dmitry
Dmitry

๐Ÿ’ป - Wachiou BOURAรMA
Wachiou BOURAรMA

๐Ÿ’ป ๐Ÿ’ฌ ๐Ÿ’ผ ๐Ÿ–‹ ๐Ÿ“– ๐Ÿค” ๐Ÿ“ฃ โš ๏ธ ๐ŸŒ โœ… ๐Ÿ““ - David Akim
David Akim

๐Ÿ’ป ๐Ÿ–‹ - Satoshi Sh.
Satoshi Sh.

๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– - Geoffrey Logovi
Geoffrey Logovi

๐ŸŽจ ๐ŸŒ ๐Ÿ“– ๐Ÿ–‹ โœ… ๐Ÿ‘€ ๐Ÿ’ป ๐Ÿ“ ๐Ÿ“น ๐Ÿ› ๐Ÿ’ก ๐Ÿ“ฃ ๐Ÿ“† ๐Ÿค” ๐Ÿ”Œ - Mikal
Mikal

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ“– ๐Ÿค” ๐Ÿง‘โ€๐Ÿซ โœ… + Obasoro
Obasoro

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿš‡ ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ โš ๏ธ ๐Ÿ”ง ๐Ÿ““ + Dmitry
Dmitry

๐Ÿ’ป + Wachiou BOURAรMA
Wachiou BOURAรMA

๐Ÿ’ป ๐Ÿ’ฌ ๐Ÿ’ผ ๐Ÿ–‹ ๐Ÿ“– ๐Ÿค” ๐Ÿ“ฃ โš ๏ธ ๐ŸŒ โœ… ๐Ÿ““ + David Akim
David Akim

๐Ÿ’ป ๐Ÿ–‹ + Satoshi Sh.
Satoshi Sh.

๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– + Geoffrey Logovi
Geoffrey Logovi

๐ŸŽจ ๐ŸŒ ๐Ÿ“– ๐Ÿ–‹ โœ… ๐Ÿ‘€ ๐Ÿ’ป ๐Ÿ“ ๐Ÿ“น ๐Ÿ› ๐Ÿ’ก ๐Ÿ“ฃ ๐Ÿ“† ๐Ÿค” ๐Ÿ”Œ + Mikal
Mikal

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ“– ๐Ÿค” ๐Ÿง‘โ€๐Ÿซ โœ… - Tooba Jamal
Tooba Jamal

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿค” ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ“ข ๐Ÿ”ง ๐ŸŒ โœ… - Zeeshan Mukhtar
Zeeshan Mukhtar

๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿ‘€ โš ๏ธ ๐ŸŒ โœ… + Tooba Jamal
Tooba Jamal

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿค” ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ“ข ๐Ÿ”ง ๐ŸŒ โœ… + Zeeshan Mukhtar
Zeeshan Mukhtar

๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿ‘€ โš ๏ธ ๐ŸŒ โœ… Jasmine
Jasmine

โœ… - Ajiboso Adeola
Ajiboso Adeola

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ - Jesse Weigel
Jesse Weigel

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ“น ๐Ÿ‘€ - Virginie
Virginie

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿค” ๐ŸŒ - Vaibhav Patel
Vaibhav Patel

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐ŸŽจ ๐Ÿค” โš ๏ธ + Ajiboso Adeola
Ajiboso Adeola

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ + Jesse Weigel
Jesse Weigel

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ“น ๐Ÿ‘€ + Virginie
Virginie

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿค” ๐ŸŒ + Vaibhav Patel
Vaibhav Patel

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐ŸŽจ ๐Ÿค” โš ๏ธ - Harlimat Odunola
Harlimat Odunola

๐Ÿ’ป ๐Ÿ“ ๐Ÿ“– ๐Ÿ–‹ ๐Ÿ’ก ๐Ÿค” ๐Ÿ‘€ โš ๏ธ ๐ŸŒ โœ… - Mi1King
Mi1King

๐Ÿ› ๐Ÿ“ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ” ๐Ÿ›ก๏ธ โœ… ๐ŸŒ - Collins O. Odhiambo
Collins O. Odhiambo

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ป ๐Ÿ“– ๐Ÿš‡ ๐Ÿšง - Fatima Aminu
Fatima Aminu

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ“– โœ… - Lindsey Howard
Lindsey Howard

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿšง ๐Ÿ”ฌ ๐Ÿ”ง โœ… - Emily Marie Ahtรบnan
Emily Marie Ahtรบnan

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ - Sunny Gandhwani
Sunny Gandhwani

๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ’ก ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿ”Œ ๐Ÿ“† + Harlimat Odunola
Harlimat Odunola

๐Ÿ’ป ๐Ÿ“ ๐Ÿ“– ๐Ÿ–‹ ๐Ÿ’ก ๐Ÿค” ๐Ÿ‘€ โš ๏ธ ๐ŸŒ โœ… + Mi1King
Mi1King

๐Ÿ› ๐Ÿ“ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ” ๐Ÿ›ก๏ธ โœ… ๐ŸŒ + Collins O. Odhiambo
Collins O. Odhiambo

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ป ๐Ÿ“– ๐Ÿš‡ ๐Ÿšง + Fatima Aminu
Fatima Aminu

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ“– โœ… + Lindsey Howard
Lindsey Howard

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿšง ๐Ÿ”ฌ ๐Ÿ”ง โœ… + Emily Marie Ahtรบnan
Emily Marie Ahtรบnan

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ + Sunny Gandhwani
Sunny Gandhwani

๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ’ก ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿ”Œ ๐Ÿ“† Alejandro Saavedra
Alejandro Saavedra

๐Ÿ”ฌ Brian Silah
Brian Silah

๐Ÿ’ก - Mazhar saifi
Mazhar saifi

๐Ÿ’ป - Jessica Wilkins
Jessica Wilkins

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“† ๐Ÿ‘€ โš ๏ธ ๐Ÿ““ - safacade009
safacade009

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐ŸŒ โœ… ๐Ÿ““ ๐Ÿ“น - Ezekiel Udiomuno
Ezekiel Udiomuno

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿค” ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”Œ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐Ÿ““ - Tung Pham
Tung Pham

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ’ก ๐Ÿšง - - - Msrimpson
Msrimpson

๐Ÿ’ป - Iza Zamorska-Wasielak
Iza Zamorska-Wasielak

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿค” ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”ฃ - Kamari Moore
Kamari Moore

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป โš ๏ธ - Sadeed pv
Sadeed pv

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ“† ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐ŸŒ โœ… - Sandeep Pal
Sandeep Pal

๐Ÿ’ป ๐Ÿ“– ๐Ÿค” ๐Ÿ’ก ๐Ÿ”ฌ ๐Ÿ’ฌ ๐ŸŒ - Armando Diaz
Armando Diaz

๐Ÿ’ป - Vaibhav Dhotre
Vaibhav Dhotre

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ“ ๐Ÿ“– ๐Ÿ–‹ ๐Ÿ’ก ๐Ÿค” ๐Ÿ‘€ โš ๏ธ ๐ŸŒ โœ… - - - solenessa
solenessa

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿš‡ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ““ - allwynvarghese
allwynvarghese

๐Ÿ’ป ๐Ÿ““ - Kennedy Musau
Kennedy Musau

๐Ÿ’ป ๐Ÿค” - TejsinghDhaosriya
TejsinghDhaosriya

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ““ - Victor Villca
Victor Villca

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿค” ๐Ÿ“– ๐Ÿ“ข ๐ŸŒ - peachjelly13
peachjelly13

๐Ÿ’ป ๐Ÿ–‹ ๐Ÿค” - Brandon
Brandon

๐Ÿ’ฌ ๐Ÿ’ป - - - Kieran McDonough
Kieran McDonough

๐Ÿ–‹ ๐Ÿ“– ๐Ÿ’ก - BrianMunsey
BrianMunsey

๐Ÿ’ป ๐Ÿค” ๐ŸŽจ ๐Ÿ› - Efe Can Kara
Efe Can Kara

๐Ÿ’ป ๐Ÿ’ก ๐Ÿค” ๐ŸŒ โœ… - Mugabe Nshuti Ignace
Mugabe Nshuti Ignace

๐Ÿ’ป ๐Ÿค” ๐Ÿ“– ๐Ÿ›ก๏ธ โœ… ๐Ÿ› ๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ก - tech-kishore
tech-kishore

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ป - HyoSung "H" Bidol-Lee
HyoSung "H" Bidol-Lee

๐Ÿ“– - Snehal Khot
Snehal Khot

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ’ก ๐Ÿšง ๐Ÿ”Œ - - - JayBee
JayBee

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ ๐Ÿ“น - Edwin Hung
Edwin Hung

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿค” ๐Ÿ“† ๐Ÿ”ฌ ๐ŸŒ - Chase Corbitt
Chase Corbitt

๐Ÿ’ป โœ… ๐Ÿ’ก ๐Ÿค” - Ashley
Ashley

๐Ÿ’ป ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿšง - Atharva
Atharva

๐Ÿ“– ๐ŸŒ - Tamale1
Tamale1

๐Ÿ’ป ๐Ÿ“– ๐Ÿšง - Cent
Cent

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿค” ๐Ÿšง ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ“ข โœ… - - - Kaz Smino
Kaz Smino

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ ๐Ÿ“น + Mazhar saifi
Mazhar saifi

๐Ÿ’ป + Jessica Wilkins
Jessica Wilkins

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“† ๐Ÿ‘€ โš ๏ธ ๐Ÿ““ + safacade009
safacade009

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐ŸŒ โœ… ๐Ÿ““ ๐Ÿ“น + Ezekiel Udiomuno
Ezekiel Udiomuno

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿค” ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”Œ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐Ÿ““ + Tung Pham
Tung Pham

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ’ก ๐Ÿšง + + + Msrimpson
Msrimpson

๐Ÿ’ป + Iza Zamorska-Wasielak
Iza Zamorska-Wasielak

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿค” ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”ฃ + Kamari Moore
Kamari Moore

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป โš ๏ธ + Sadeed pv
Sadeed pv

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ“† ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐ŸŒ โœ… + Sandeep Pal
Sandeep Pal

๐Ÿ’ป ๐Ÿ“– ๐Ÿค” ๐Ÿ’ก ๐Ÿ”ฌ ๐Ÿ’ฌ ๐ŸŒ + Armando Diaz
Armando Diaz

๐Ÿ’ป + Vaibhav Dhotre
Vaibhav Dhotre

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ“ ๐Ÿ“– ๐Ÿ–‹ ๐Ÿ’ก ๐Ÿค” ๐Ÿ‘€ โš ๏ธ ๐ŸŒ โœ… + + + solenessa
solenessa

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿš‡ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ““ + allwynvarghese
allwynvarghese

๐Ÿ’ป ๐Ÿ““ + Kennedy Musau
Kennedy Musau

๐Ÿ’ป ๐Ÿค” + TejsinghDhaosriya
TejsinghDhaosriya

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ““ + Victor Villca
Victor Villca

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿค” ๐Ÿ“– ๐Ÿ“ข ๐ŸŒ + peachjelly13
peachjelly13

๐Ÿ’ป ๐Ÿ–‹ ๐Ÿค” + Brandon
Brandon

๐Ÿ’ฌ ๐Ÿ’ป + + + Kieran McDonough
Kieran McDonough

๐Ÿ–‹ ๐Ÿ“– ๐Ÿ’ก + BrianMunsey
BrianMunsey

๐Ÿ’ป ๐Ÿค” ๐ŸŽจ ๐Ÿ› + Efe Can Kara
Efe Can Kara

๐Ÿ’ป ๐Ÿ’ก ๐Ÿค” ๐ŸŒ โœ… + Mugabe Nshuti Ignace
Mugabe Nshuti Ignace

๐Ÿ’ป ๐Ÿค” ๐Ÿ“– ๐Ÿ›ก๏ธ โœ… ๐Ÿ› ๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ก + tech-kishore
tech-kishore

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ป + HyoSung "H" Bidol-Lee
HyoSung "H" Bidol-Lee

๐Ÿ“– + Snehal Khot
Snehal Khot

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ’ก ๐Ÿšง ๐Ÿ”Œ + + + JayBee
JayBee

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ ๐Ÿ“น + Edwin Hung
Edwin Hung

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿค” ๐Ÿ“† ๐Ÿ”ฌ ๐ŸŒ + Chase Corbitt
Chase Corbitt

๐Ÿ’ป โœ… ๐Ÿ’ก ๐Ÿค” + Ashley
Ashley

๐Ÿ’ป ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿšง + Atharva
Atharva

๐Ÿ“– ๐ŸŒ + Tamale1
Tamale1

๐Ÿ’ป ๐Ÿ“– ๐Ÿšง + Cent
Cent

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿค” ๐Ÿšง ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ“ข โœ… + + + Kaz Smino
Kaz Smino

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ ๐Ÿ“น Sophia Umaru
Sophia Umaru

๐Ÿ’ฌ ๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ โœ… ๐Ÿ““ - nick
nick

๐Ÿ’ป ๐Ÿ“– ๐Ÿš‡ - Julien
Julien

๐Ÿ“– - Johannes Grimm
Johannes Grimm

๐Ÿ› ๐Ÿ’ป ๐Ÿš‡ ๐Ÿ”ฌ ๐Ÿ”ง - Youssouph Manรฉ
Youssouph Manรฉ

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿ”ฌ ๐Ÿ”ง - Vivine Assokane
Vivine Assokane

๐Ÿ› ๐Ÿ“– ๐Ÿ“† ๐ŸŒ + nick
nick

๐Ÿ’ป ๐Ÿ“– ๐Ÿš‡ + Julien
Julien

๐Ÿ“– + Johannes Grimm
Johannes Grimm

๐Ÿ› ๐Ÿ’ป ๐Ÿš‡ ๐Ÿ”ฌ ๐Ÿ”ง + Youssouph Manรฉ
Youssouph Manรฉ

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿ”ฌ ๐Ÿ”ง + Vivine Assokane
Vivine Assokane

๐Ÿ› ๐Ÿ“– ๐Ÿ“† ๐ŸŒ - Chris Chen
Chris Chen

๐Ÿ“– - haimantika mitra
haimantika mitra

๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– - Alberto Josรฉ
Alberto Josรฉ

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ’ก โœ… ๐Ÿ“– + Chris Chen
Chris Chen

๐Ÿ“– + haimantika mitra
haimantika mitra

๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– + Alberto Josรฉ
Alberto Josรฉ

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ’ก โœ… ๐Ÿ“– neeraj rawat
neeraj rawat

๐Ÿ–‹ - Safa Anฤฑl ATASOY
Safa Anฤฑl ATASOY

๐Ÿ’ป ๐Ÿ“– ๐ŸŒ - Caniggia Thompson
Caniggia Thompson

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ โš ๏ธ โœ… ๐Ÿ““ - Jonathan Woytsek
Jonathan Woytsek

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– - - - ๐Ÿ…ฟ๏ธadi
๐Ÿ…ฟ๏ธadi

๐Ÿ› - JohnKagunda
JohnKagunda

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” โš ๏ธ ๐Ÿ”ง ๐Ÿ““ - LuisCFunes
LuisCFunes

๐Ÿ› ๐Ÿ’ป ๐ŸŒ - Erik
Erik

๐Ÿ’ป ๐Ÿค” ๐Ÿšง ๐Ÿ”ฌ - Ahmet RaลŸit SAYLIK
Ahmet RaลŸit SAYLIK

โœ… - John Mwendwa
John Mwendwa

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” - Simon Gideon
Simon Gideon

๐Ÿ’ป - - - Michaella Rodriguez
Michaella Rodriguez

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿง‘โ€๐Ÿซ โœ… - James Emmanuel
James Emmanuel

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ โš ๏ธ ๐Ÿ”ง ๐Ÿ““ - Laura OBrien
Laura OBrien

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿ’ต ๐Ÿš‡ ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”Œ ๐Ÿ›ก๏ธ ๐Ÿ“ข ๐Ÿ”ง ๐Ÿ“น - Chitral Patil
Chitral Patil

๐Ÿ’ฌ ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ โœ… - rohitkrsoni
rohitkrsoni

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ“– ๐Ÿšง ๐Ÿ”ฌ โš ๏ธ - Alex Oliva
Alex Oliva

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ’ก ๐Ÿ‘€ ๐Ÿ““ - KAANAN
KAANAN

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿค” โš ๏ธ โœ… - - - emma
emma

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿšง - Paul Wade
Paul Wade

๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– - CatCat Ice
CatCat Ice

๐Ÿ–‹ โœ… - Kenth
Kenth

๐ŸŽจ ๐Ÿ’ก ๐Ÿค” ๐Ÿง‘โ€๐Ÿซ ๐ŸŒ - Manuela Flores
Manuela Flores

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿ’ก ๐Ÿšง ๐Ÿ”Œ โš ๏ธ - Asiri Alwis
Asiri Alwis

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿ“† ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ“ข ๐ŸŒ - sunggeorge
sunggeorge

๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ - - - Aditya Kumar Sahu
Aditya Kumar Sahu

๐Ÿ’ฌ ๐Ÿ’ป ๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ ๐Ÿ“น - Mohamed Adam Ata
Mohamed Adam Ata

๐Ÿ’ฌ โœ… - Dhananjay Chitale
Dhananjay Chitale

๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ ๐Ÿ“น - alekyluken
alekyluken

๐Ÿ’ป ๐Ÿ”ฃ - Deepak Kumar Chaudhary
Deepak Kumar Chaudhary

๐Ÿ› ๐Ÿ“ - Alexander Choji
Alexander Choji

๐Ÿ’ฌ ๐Ÿ› - Jmal Mohamed Ali
Jmal Mohamed Ali

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿค” ๐Ÿšง ๐Ÿ‘€ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… - - - Alok Jadhao
Alok Jadhao

๐Ÿ’ฌ ๐Ÿ’ป - overfero
overfero

โœ… ๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿค” ๐Ÿ”ฌ - HarshDev Tripathi
HarshDev Tripathi

๐Ÿ’ฌ ๐Ÿ› ๐ŸŽจ ๐Ÿ’ป ๐Ÿค” ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ”ฌ ๐Ÿ›ก๏ธ โš ๏ธ ๐Ÿ”ง - Suryakant Kumar
Suryakant Kumar

๐Ÿ’ฌ ๐Ÿ› - Scott Chen
Scott Chen

๐Ÿ’ป - Enamul Hassan
Enamul Hassan

๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿ” ๐Ÿค” ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“† ๐Ÿ”ฌ ๐Ÿ›ก๏ธ ๐Ÿ“ข โœ… ๐Ÿ““ - Victor Oldensand
Victor Oldensand

๐Ÿ› ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿค” ๐Ÿ“† - - - Zaira
Zaira

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ› ๐Ÿ’ป ๐ŸŽจ ๐Ÿ“– ๐Ÿ‘€ ๐ŸŒ ๐Ÿ““ - Rubin
Rubin

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฃ ๐Ÿ”ฌ โœ… - Ehsanullah Haidary
Ehsanullah Haidary

๐Ÿ› ๐Ÿ’ป ๐ŸŽจ ๐Ÿ“– - Favour Achara
Favour Achara

๐Ÿ“ ๐Ÿค” - hediyetapan
hediyetapan

๐Ÿ’ป - Jahid Imran
Jahid Imran

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ’ก ๐Ÿ”ฌ ๐Ÿ›ก๏ธ โš ๏ธ - Marcella Harris
Marcella Harris

๐Ÿ–‹ ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿค” ๐Ÿ”ฌ ๐Ÿ““ - - - Alfred Emmanuel
Alfred Emmanuel

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿšง - Vamsi Krishna Sethu
Vamsi Krishna Sethu

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿ“ฆ ๐Ÿ”ฌ โœ… - Ibukun Demehin
Ibukun Demehin

๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ”ฌ โœ… ๐Ÿค” ๐Ÿ““ - Issakha
Issakha

๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ›ก๏ธ - CHANDRATRE MAYANK MANDAR
CHANDRATRE MAYANK MANDAR

๐Ÿ› ๐Ÿ’ป ๐Ÿ“ข - Shubham Kumar
Shubham Kumar

๐Ÿ’ฌ ๐Ÿ› - YoungGunner14
YoungGunner14

๐Ÿ“ฃ - - - Birat Gautam
Birat Gautam

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”ฌ ๐Ÿ‘€ โœ… ๐Ÿ“น - Kristi Ingco
Kristi Ingco

๐Ÿ› ๐Ÿ““ - Puneet khatri
Puneet khatri

๐Ÿ’ฌ ๐Ÿ› - Izundu Chinonso Emmanuel
Izundu Chinonso Emmanuel

๐Ÿ–‹ โš ๏ธ โœ… - W A T Amasha Fernando
W A T Amasha Fernando

๐Ÿ’ฌ ๐Ÿ› - Jacob Smith
Jacob Smith

๐Ÿ’ฌ ๐Ÿ› - McRae Petrey
McRae Petrey

๐Ÿ› ๐Ÿ“– - - - Terry.He
Terry.He

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐ŸŽจ - Cynthia
Cynthia

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ–‹ ๐Ÿ“‹ ๐Ÿค” ๐Ÿ“† - Shubham Sharma
Shubham Sharma

๐Ÿ“– - Wybson Santana
Wybson Santana

โœ… - Zier0Code
Zier0Code

๐Ÿ’ฌ ๐Ÿ› - Borcila Vasile
Borcila Vasile

๐Ÿ› ๐Ÿ’ป - David Ma
David Ma

๐Ÿ’ฌ ๐Ÿ““ - - - ///\).tkn
///\).tkn

๐Ÿ’ฌ ๐Ÿ’ก ๐Ÿค” ๐ŸŒ - Franklin Pineda
Franklin Pineda

๐Ÿ› ๐ŸŒ - Soufiane Joumal
Soufiane Joumal

๐Ÿ’ป ๐ŸŽจ - Md. Mehedi Hasan
Md. Mehedi Hasan

๐Ÿ’ฌ ๐Ÿ› - eka
eka

๐Ÿ’ฌ ๐Ÿ› - Aaron Pedwell
Aaron Pedwell

๐Ÿ“– ๐Ÿ’ก ๐Ÿšง โœ… - Harsh Khandelwal
Harsh Khandelwal

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿšง ๐Ÿ“† ๐Ÿ‘€ โœ… ๐Ÿ“ข - - - Zeth Danielsson
Zeth Danielsson

๐Ÿ’ป ๐Ÿค” ๐Ÿš‡ ๐Ÿšง - koja-amir
koja-amir

๐Ÿ”ฃ - Mrutunjay Kinagi
Mrutunjay Kinagi

๐Ÿ“ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ‘€ - Firdous2307
Firdous2307

๐Ÿ’ป ๐Ÿ“– ๐Ÿš‡ ๐Ÿšง ๐Ÿ›ก๏ธ โš ๏ธ ๐Ÿ”ง - Samar_Mestiri
Samar_Mestiri

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“‹ ๐Ÿค” - Shristi Rawat
Shristi Rawat

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป - Gaffar
Gaffar

๐Ÿ’ฌ ๐Ÿ› + Safa Anฤฑl ATASOY
Safa Anฤฑl ATASOY

๐Ÿ’ป ๐Ÿ“– ๐ŸŒ + Caniggia Thompson
Caniggia Thompson

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ โš ๏ธ โœ… ๐Ÿ““ + Jonathan Woytsek
Jonathan Woytsek

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– - Sridhar Moturu
Sridhar Moturu

๐Ÿ’ป - Abraham Ayamigah
Abraham Ayamigah

๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿš‡ - Emmanuel Odero
Emmanuel Odero

๐Ÿ› ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿš‡ ๐Ÿšง โš ๏ธ - wisdom oladipupo
wisdom oladipupo

๐Ÿ’ฌ ๐Ÿ› - Fahim Al Jadid
Fahim Al Jadid

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿ““ - Kolapo Wariz
Kolapo Wariz

๐Ÿ’ก ๐Ÿ’ฌ ๐Ÿ› - anka
anka

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ - - - Hugh Ferguson
Hugh Ferguson

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ โœ… - Ashen Thilakarathna
Ashen Thilakarathna

๐Ÿ’ฌ ๐Ÿ› - Chinmay@234
Chinmay@234

๐Ÿ’ป ๐Ÿ’ต ๐Ÿค” ๐Ÿš‡ ๐Ÿ“ฃ ๐Ÿ“ข โœ… ๐Ÿ“น - Satyam Kumar
Satyam Kumar

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ’ป - Mohana Misra
Mohana Misra

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿค” ๐Ÿšง ๐Ÿ“† ๐Ÿ”ฌ ๐Ÿ‘€ โœ… - Lorenz De Robles
Lorenz De Robles

๐Ÿ’ป โœ… - Liaxo
Liaxo

๐Ÿ’ป ๐ŸŽจ ๐Ÿ“– ๐Ÿš‡ ๐Ÿ“น - - - H. Nhi (Alex)
H. Nhi (Alex)

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿ“† ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ - Udana Nimsara
Udana Nimsara

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿ‘€ ๐Ÿ› ๐ŸŒ โœ… - Olivia Laurel
Olivia Laurel

๐Ÿ’ฌ ๐Ÿ’ป ๐ŸŽจ ๐Ÿ““ - Sanketh Kumar
Sanketh Kumar

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ“– - Dehan
Dehan

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ - Jahtofunmi Osho
Jahtofunmi Osho

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿ’ก - Ruben amadei
Ruben amadei

๐Ÿ’ฌ ๐Ÿ“– ๐ŸŒ - - - Jeffarson Amenya
Jeffarson Amenya

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ“– ๐Ÿ‘€ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐ŸŽจ ๐Ÿค” ๐Ÿšง ๐Ÿ“ข ๐ŸŒ โœ… ๐Ÿ“น - Andrew Martinez
Andrew Martinez

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐Ÿ““ - Luciano M.
Luciano M.

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง โœ… - adaniel105
adaniel105

๐Ÿ’ป ๐Ÿ“– ๐Ÿš‡ ๐Ÿ”Œ ๐Ÿ”ฌ - Mukami
Mukami

๐Ÿ’ป ๐Ÿ”ฃ - Susan Githaiga
Susan Githaiga

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– - TaeHo Kim
TaeHo Kim

๐Ÿ’ฌ ๐Ÿ› โš ๏ธ ๐ŸŒ ๐Ÿ““ - - - Ilyes Medjedoub
Ilyes Medjedoub

๐Ÿค” โœ… - Ivan Guzman
Ivan Guzman

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐ŸŽจ ๐Ÿ“– ๐Ÿค” ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ‘€ ๐ŸŒ - Patel Yogi Chetanbhai
Patel Yogi Chetanbhai

๐Ÿ’ฌ - Sylus Abel
Sylus Abel

๐Ÿ’ป ๐Ÿ’ฌ ๐Ÿ› ๐ŸŽจ ๐Ÿšง ๐Ÿ”ฌ ๐Ÿ‘€ โš ๏ธ ๐ŸŒ โœ… - Diego de Miranda
Diego de Miranda

๐Ÿ› ๐Ÿ’ป ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿค” ๐ŸŒ ๐Ÿ““ - errantpianist
errantpianist

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”ฌ ๐Ÿ‘€ โš ๏ธ โœ… ๐Ÿ““ - Ankit Ahuja
Ankit Ahuja

๐Ÿ’ฌ ๐Ÿ“น - - - Ankit Kumar Jha
Ankit Kumar Jha

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ - ray
ray

๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ’ป ๐ŸŽจ ๐Ÿค” ๐Ÿ“ข ๐Ÿ“น - HakeemYusuff
HakeemYusuff

๐Ÿ’ป ๐Ÿ“– ๐Ÿšง - Luca Wang
Luca Wang

๐Ÿ’ป ๐Ÿš‡ ๐Ÿ›ก๏ธ - Brody
Brody

๐Ÿ’ฌ ๐Ÿ› - David Chuku
David Chuku

๐Ÿ› - iris mariah kurien
iris mariah kurien

๐Ÿ–‹ - - - Aftar Ahmad Sami
Aftar Ahmad Sami

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿค” ๐Ÿš‡ ๐Ÿ”ฌ ๐Ÿ”ง - Jacob Crosser
Jacob Crosser

๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– - Manoj Thilakarathna
Manoj Thilakarathna

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿค” - Tobi
Tobi

๐Ÿ“– ๐Ÿ’ก - Mohamad Badrawy
Mohamad Badrawy

๐Ÿ’ฌ - Rijan Shrestha
Rijan Shrestha

๐Ÿ““ ๐Ÿ’ฌ - SnowyCrest
SnowyCrest

๐Ÿ’ป - - - Muskan Seth
Muskan Seth

๐Ÿ› ๐Ÿ“– ๐Ÿ’ก ๐Ÿ’ป ๐ŸŽจ - MD. SHAFAYAT MAHIN
MD. SHAFAYAT MAHIN

๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ”ง โœ… - Justin M Edenbaum
Justin M Edenbaum

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ“น - Rhizvo
Rhizvo

๐Ÿ“ฃ - Nick Hanson Sr
Nick Hanson Sr

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป - muou
muou

๐Ÿ’ฌ ๐Ÿ› - Cristian Campos
Cristian Campos

๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ”ฌ ๐ŸŒ - - - Hritik Yadav
Hritik Yadav

๐Ÿ’ฌ ๐Ÿ› - Angel Mancilla
Angel Mancilla

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ“– ๐Ÿ” ๐Ÿค” ๐Ÿšง ๐Ÿ”ฌ ๐Ÿ›ก๏ธ โš ๏ธ ๐ŸŒ โœ… - Ebube Ochemba
Ebube Ochemba

๐Ÿ› - Janzen Go
Janzen Go

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐ŸŽจ ๐Ÿ“– ๐Ÿ“ฃ โš ๏ธ ๐Ÿ”ง ๐ŸŒ - Vianney Yovo
Vianney Yovo

๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ”ฃ - Pedro Palma Villanueva
Pedro Palma Villanueva

๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿšง ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ‘€ โš ๏ธ ๐ŸŒ - @notavailable4u
@notavailable4u

๐Ÿ’ฌ - - - Spc
Spc

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿค” ๐ŸŒ - Ernest Baker
Ernest Baker

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ‘€ ๐Ÿ›ก๏ธ โš ๏ธ ๐Ÿ”ง โœ… - Pablo
Pablo

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ‘€ ๐Ÿ›ก๏ธ - ValLee4
ValLee4

โœ… - Richard Samuel
Richard Samuel

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿค” - Mohammed Alzoubi
Mohammed Alzoubi

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿค” ๐Ÿ”ฌ - 0xn0b174
0xn0b174

๐Ÿ’ฌ ๐Ÿ› - - - QUxPTA
QUxPTA

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿšง - Luxolo Mdingi
Luxolo Mdingi

๐Ÿ’ฌ ๐Ÿ› - Madevanni
Madevanni

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ“– - doraemon2200
doraemon2200

๐Ÿ’ป ๐Ÿ‘€ - Muhammad Muzammil Loya
Muhammad Muzammil Loya

๐Ÿ’ฌ ๐Ÿ› - vivienogoun
vivienogoun

๐Ÿ–‹ ๐Ÿ”ฃ - Rob Heaton
Rob Heaton

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿค” ๐Ÿšง โš ๏ธ - - - Voaides Negustor Robert
Voaides Negustor Robert

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ“– - Tanishq Vaishnav
Tanishq Vaishnav

๐Ÿ’ฌ ๐Ÿ› ๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ป ๐ŸŽจ ๐Ÿ“– ๐Ÿš‡ ๐Ÿšง ๐Ÿ”Œ - Andres Rangel
Andres Rangel

๐Ÿ’ป ๐Ÿ“– ๐Ÿšง - KOUSTUBH BADSHAH
KOUSTUBH BADSHAH

๐Ÿ’ฌ ๐Ÿ› ๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ - Porter Taylor
Porter Taylor

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– - drazerd
drazerd

๐Ÿ’ฌ ๐Ÿ› ๐ŸŽจ ๐Ÿ“– ๐Ÿšง ๐Ÿ‘€ - Simpa
Simpa

๐Ÿ’ป - - - Tomas Darquier
Tomas Darquier

๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿš‡ - Matheus Gomes Dias
Matheus Gomes Dias

๐Ÿ’ป ๐Ÿ“– ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ โš ๏ธ ๐ŸŒ - Jingjie Gao
Jingjie Gao

๐Ÿ’ฌ - Turdle
Turdle

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ โš ๏ธ ๐Ÿ”ง โœ… ๐Ÿ““ - Edwin Kuruvila
Edwin Kuruvila

๐Ÿ’ฌ ๐Ÿ› - Sidney Baraka Muriuki
Sidney Baraka Muriuki

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ’ป ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– - darlopvil
darlopvil

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ’ก ๐Ÿ”ฌ ๐Ÿ›ก๏ธ โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… - - - AKINTADE OLUMUYIWA
AKINTADE OLUMUYIWA

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿ”ฌ โœ… - Andrew Sameh
Andrew Sameh

๐Ÿ“– ๐Ÿšง - Algacyr Melo
Algacyr Melo

๐Ÿ“– - Ayush Shukla
Ayush Shukla

๐Ÿ’ป - Hardik S
Hardik S

๐Ÿ› ๐Ÿ’ป ๐Ÿ”ฃ - Ghaith
Ghaith

๐ŸŽจ ๐Ÿ“– ๐Ÿ’ป ๐Ÿ–‹ - Isaiah Juma
Isaiah Juma

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ’ก ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข ๐Ÿ”ง โœ… ๐Ÿ““ - - - Archit Kumar
Archit Kumar

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ”Š ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐ŸŽจ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿ’ต ๐Ÿ” ๐Ÿค” ๐Ÿš‡ ๐Ÿšง ๐Ÿง‘โ€๐Ÿซ ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ“ฃ ๐Ÿ”ฌ ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง ๐ŸŒ โœ… ๐Ÿ““ ๐Ÿ“น - Aswin. M
Aswin. M

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿค” ๐Ÿšง ๐Ÿ“ฆ ๐Ÿ”Œ ๐Ÿ“† ๐Ÿ‘€ ๐Ÿ›ก๏ธ ๐Ÿ“ข โš ๏ธ ๐Ÿ”ง - wdy3827
wdy3827

๐Ÿ’ฌ ๐Ÿ› - Mohd Harish
Mohd Harish

๐Ÿ’ป ๐ŸŽจ ๐Ÿค” ๐Ÿ”ฌ - Jake Cipri
Jake Cipri

๐Ÿ› ๐Ÿ’ป ๐Ÿ”ฃ ๐Ÿ“– - Tawan Barbosa da Silva
Tawan Barbosa da Silva

๐Ÿ’ฌ ๐Ÿ“ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป ๐Ÿ–‹ ๐Ÿ”ฃ ๐Ÿ“– ๐Ÿ“‹ ๐Ÿ’ก ๐Ÿค” ๐Ÿš‡ ๐Ÿ”ฌ ๐Ÿ›ก๏ธ โš ๏ธ ๐ŸŒ โœ… - Gideon Fiadowu Norkplim
Gideon Fiadowu Norkplim

๐Ÿ’ฌ ๐Ÿ› - - - Theophilus Ige
Theophilus Ige

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ› - Danjuma Ibrahim
Danjuma Ibrahim

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ’ฌ ๐Ÿ› - Cyril Stafford Giri
Cyril Stafford Giri

๐Ÿ’ป ๐ŸŽจ - Michael Cortese
Michael Cortese

๐Ÿ› ๐Ÿ’ป ๐Ÿ’ต - Omm P
Omm P

๐Ÿ’ฌ ๐Ÿ› - Patrick Fish
Patrick Fish

๐Ÿ’ฌ ๐Ÿ’ก - Krish Gupta
Krish Gupta

๐Ÿ’ป ๐Ÿ““ - - - Akarsh Balachandran
Akarsh Balachandran

๐Ÿ“– - Nabin Bista
Nabin Bista

๐Ÿ’ฌ - - - - - - - Add your contributions - - - - - - - - - - - -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome! + ๐Ÿ…ฟ๏ธadi
๐Ÿ…ฟ๏ธadi

๐Ÿ› + JohnKagunda
JohnKagunda

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป contributors/testuser.json + + # Commit and push to trigger the action + git add contributors/testuser.json + git commit -m "test: add test contributor" + git push + ``` + +2. **Verify the GitHub Action runs** and updates the README +3. **Remove the test file** after successful verification + +### Step 3: Update Course Materials (Within 1 week) +1. **Update the course links** to point to new instructions: + - From: "Edit README.md directly" + - To: "Create contributor JSON file" + +2. **Update specific sections:** + - [Let's Get Practical](https://opensauced.pizza/learn/intro-to-oss/how-to-contribute-to-open-source#lets-get-practical) + - Any screenshots or examples showing the old process + +### Step 4: Communicate Changes (Within 1 week) +1. **Pin an announcement issue** using content from [docs/ANNOUNCEMENT.md](ANNOUNCEMENT.md) +2. **Update social media** if the course is promoted there +3. **Notify course instructors** about the changes + +### Step 5: Handle Transition Period (1-2 weeks) +1. **Monitor for confused contributors** who might still try the old method +2. **Be ready to help** with questions about the new process +3. **Update any existing open PRs** that follow the old method + +### Step 6: Cleanup (After 2 weeks) +1. **Remove old npm scripts** that are no longer needed: + ```bash + # Keep for backwards compatibility initially, remove later + npm run contributors:add + npm run contributors:generate + ``` + +2. **Archive old documentation** that references the manual process + +## Success Metrics + +### Technical Metrics +- โœ… Zero merge conflicts on contributor PRs +- โœ… GitHub Actions run successfully +- โœ… All validation passes +- โœ… README updates automatically + +### User Experience Metrics +- ๐Ÿ“Š **Time to contribute**: Should be faster (no npm commands needed) +- ๐Ÿ“Š **Success rate**: Higher (no conflict resolution needed) +- ๐Ÿ“Š **Support requests**: Fewer questions about merge conflicts + +### Expected Outcomes +- **Before**: ~50% of PRs had merge conflicts +- **After**: 0% of contributor PRs should have conflicts +- **Maintainer time**: Reduced by ~75% (no manual conflict resolution) +- **Contributor experience**: Much smoother for beginners + +## Rollback Plan + +If issues arise, rollback is simple: + +1. **Revert the GitHub Actions workflows** (disable them) +2. **Restore old PR template** and contributing guidelines +3. **Keep the JSON files** as they don't interfere with the old system +4. **Contributors can go back** to the old `npm run contributors:add` process + +The system is designed to be backwards compatible during the transition. + +## Support During Deployment + +### For Contributors +- **New process**: Follow [docs/guides/contributor-guide.md](docs/guides/contributor-guide.md) +- **Old PRs**: Can be merged as-is or converted to new format +- **Questions**: Use GitHub Discussions or Issues + +### For Maintainers +- **Validation**: Use `npm run contributors:validate` +- **Manual processing**: GitHub Actions handle everything automatically +- **Troubleshooting**: Check workflow logs for any issues + +## Post-Deployment Tasks + +### Week 1 +- [ ] Monitor GitHub Actions for failures +- [ ] Respond to contributor questions quickly +- [ ] Update course materials with new screenshots + +### Week 2-4 +- [ ] Collect feedback from new contributors +- [ ] Fine-tune validation rules if needed +- [ ] Update any missed documentation references + +### Month 2+ +- [ ] Analyze success metrics +- [ ] Consider additional improvements (e.g., web form for contributions) +- [ ] Share learnings with other similar projects + +## Contact + +For questions about deployment: +- Create an issue with the `deployment` label +- Tag maintainers in discussions +- Check the [Migration Guide](MIGRATION_GUIDE.md) for technical details \ No newline at end of file diff --git a/docs/MIGRATION_GUIDE.md b/docs/MIGRATION_GUIDE.md new file mode 100644 index 0000000..b0c59a8 --- /dev/null +++ b/docs/MIGRATION_GUIDE.md @@ -0,0 +1,179 @@ +# โœ… Migration Complete: Conflict-Free Contributors System + +The migration to the new conflict-free contributor system has been implemented successfully! This document explains what changed and how to use the new system. + +## What Changed? + +### Before (Old System) +- Contributors edited the README.md directly +- Used `npm run contributors:add` and `npm run contributors:generate` +- Multiple simultaneous PRs caused merge conflicts +- Beginners struggled with conflict resolution + +### After (New System) +- Contributors create individual JSON files in `contributors/` directory +- GitHub Actions automatically update the README +- Zero merge conflicts, even with simultaneous contributions +- Much more beginner-friendly + +## Implementation Status + +โœ… **310 contributor files** successfully migrated +โœ… **All validations pass** - proper JSON format +โœ… **GitHub Actions** configured and ready +โœ… **Documentation** updated and comprehensive +โœ… **README complete** with all 310 contributors displaying correctly +โœ… **Local testing** capabilities implemented + +### ๐Ÿ“ Files Created +``` +contributors/ +โ”œโ”€โ”€ example-contributor.json # Template example +โ”œโ”€โ”€ *.json # 310 migrated contributor files +โ””โ”€โ”€ .gitkeep # Ensures directory is tracked + +.github/workflows/ +โ”œโ”€โ”€ update-contributors.yml # Main automation workflow +โ”œโ”€โ”€ validate-contributors.yml # Validation for PR/push +โ”œโ”€โ”€ validate-pr.yml # PR validation and welcome +โ””โ”€โ”€ welcome-new-contributor.yml # Post-merge celebration + +scripts/ +โ”œโ”€โ”€ migrate-contributors.sh # Migration script (completed) +โ”œโ”€โ”€ validate-contributor.py # Validation utility +โ”œโ”€โ”€ test-locally.sh # Local testing +โ””โ”€โ”€ preview-contribution.py # Local preview + +docs/guides/ +โ”œโ”€โ”€ contributor-guide.md # Instructions for contributors +โ””โ”€โ”€ testing-your-contribution.md # How to test contributions + +docs/ +โ”œโ”€โ”€ TESTING_GUIDE.md # Comprehensive testing guide +โ”œโ”€โ”€ DEPLOYMENT_PLAN.md # Implementation timeline +โ””โ”€โ”€ ANNOUNCEMENT.md # Communication template +``` + +### ๐Ÿ“ Updated Documentation +- **CONTRIBUTING.md**: New process instructions +- **README.md**: Updated getting started section +- **PR Template**: Simplified for contributor additions +- **Package.json**: Added new npm scripts for local testing + +## For Contributors + +### If You're New +Simply follow the new instructions in [docs/guides/contributor-guide.md](guides/contributor-guide.md). It's much easier than the old process! + +### If You Have an Open PR (Old System) +You have two options: + +1. **Keep your existing PR**: It will still work, but might have merge conflicts +2. **Switch to new system**: + - Close your old PR + - Create a new PR with just your JSON file + - Much less likely to have conflicts + +### Converting Your Old PR to New System +1. Look at the files you changed in your old PR +2. Extract your contributor information +3. Create a new JSON file with that information: +```json +{ + "name": "Your Name From Old PR", + "github": "your-github-username", + "profile": "your-profile-url", + "contributions": ["your", "contribution", "types"] +} +``` +4. Submit new PR with just this file + +## Technical Details + +### Local Testing Capabilities + +Contributors can now test their contributions locally before submitting: + +```bash +# Quick preview - shows exactly how profile will appear +npm run contributors:preview your-username + +# Full validation - checks for errors +npm run contributors:validate + +# Complete test - generates temporary preview +npm run contributors:test your-username +``` + +### JSON File Format +```json +{ + "name": "Required: Your display name", + "github": "Required: Your GitHub username", + "profile": "Optional: Your website/profile URL", + "contributions": ["Required: Array of contribution types"] +} +``` + +### GitHub Actions Workflow +1. Detect changes to `contributors/*.json` files +2. Validate JSON format and required fields +3. Reset the all-contributors configuration +4. Process each JSON file and add to all-contributors +5. Generate the updated README +6. Commit and push changes + +### Validation +- JSON syntax validation +- Required field checking +- Contribution type validation +- Duplicate detection +- GitHub username format validation + +## Rollback Plan + +If you need to rollback to the old system: + +1. Restore the old PR template and contributing guidelines +2. Disable the new GitHub Actions workflows +3. Contributors can go back to the old `npm run contributors:add` process +4. Keep the JSON files as backup/reference + +## Benefits of New System + +โœ… **Zero merge conflicts** - Each contributor only touches their own file +โœ… **Beginner friendly** - Simple JSON file creation vs complex git operations +โœ… **Automatic processing** - No manual intervention needed from maintainers +โœ… **Scalable** - Supports unlimited simultaneous contributors +โœ… **Better validation** - Automated checks for proper format +โœ… **Maintainable** - Easier to manage individual contributor data + +## Troubleshooting + +### GitHub Action Fails +- Check the workflow logs for specific errors +- Validate JSON files using `python3 scripts/validate-contributor.py` +- Ensure all required fields are present + +### README Not Updating +- Verify the action has write permissions +- Check that the file paths in the workflow are correct +- Make sure the all-contributors config is properly reset + +### Contributors Confused +- Pin an issue explaining the new process +- Update course materials and documentation +- Direct them to [docs/guides/contributor-guide.md](guides/contributor-guide.md) + +## Support Resources + +- **For Contributors**: [docs/guides/contributor-guide.md](guides/contributor-guide.md) +- **For Testing**: [docs/guides/testing-your-contribution.md](guides/testing-your-contribution.md) +- **For Maintainers**: [docs/TESTING_GUIDE.md](TESTING_GUIDE.md) +- **Technical Details**: [docs/DEPLOYMENT_PLAN.md](DEPLOYMENT_PLAN.md) +- **Communication**: [docs/ANNOUNCEMENT.md](ANNOUNCEMENT.md) + +--- + +**๐ŸŽ‰ Migration complete!** This system eliminates merge conflicts while making contributions much more beginner-friendly. + diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..d4ee8ee --- /dev/null +++ b/docs/README.md @@ -0,0 +1,51 @@ +# Documentation Index + +This directory contains all documentation for the guestbook project. + +## ๐Ÿ“– For Contributors + +### Getting Started +- **[Contributor Guide](guides/contributor-guide.md)** - Complete instructions for adding yourself to the guestbook +- **[Testing Your Contribution](guides/testing-your-contribution.md)** - How to verify your contribution worked + +### Quick Reference +- **[Main Contributing Guidelines](../CONTRIBUTING.md)** - Overall contribution rules and process +- **[Contributors Directory](../contributors/)** - Where you add your JSON file + +## ๐Ÿ”ง For Maintainers + +### Implementation +- **[Migration Guide](MIGRATION_GUIDE.md)** - Complete migration documentation and technical details +- **[Testing Guide](TESTING_GUIDE.md)** - Comprehensive testing procedures +- **[Deployment Plan](DEPLOYMENT_PLAN.md)** - Implementation timeline and checklist + +### Communication +- **[Announcement Template](ANNOUNCEMENT.md)** - Ready-to-use announcement for the community + +## ๐ŸŽฏ Quick Navigation + +| I want to... | Go here | +|---------------|---------| +| Add myself to the guestbook | [Contributor Guide](guides/contributor-guide.md) | +| Test my contribution locally | [Testing Your Contribution](guides/testing-your-contribution.md) | +| Understand the new system | [Migration Guide](MIGRATION_GUIDE.md) | +| Report a problem | [GitHub Issues](../../issues) | +| Ask a question | [GitHub Discussions](../../discussions) | + +## ๐Ÿ“ Directory Structure + +``` +docs/ +โ”œโ”€โ”€ README.md # This index file +โ”œโ”€โ”€ MIGRATION_GUIDE.md # Complete migration documentation +โ”œโ”€โ”€ TESTING_GUIDE.md # Testing procedures +โ”œโ”€โ”€ DEPLOYMENT_PLAN.md # Implementation details +โ”œโ”€โ”€ ANNOUNCEMENT.md # Community communication template +โ””โ”€โ”€ guides/ + โ”œโ”€โ”€ contributor-guide.md # How to add yourself (for contributors) + โ””โ”€โ”€ testing-your-contribution.md # How to verify it worked +``` + +--- + +**๐ŸŽ‰ The new system eliminates merge conflicts while making contributions more beginner-friendly!** \ No newline at end of file diff --git a/docs/TESTING_GUIDE.md b/docs/TESTING_GUIDE.md new file mode 100644 index 0000000..af53aed --- /dev/null +++ b/docs/TESTING_GUIDE.md @@ -0,0 +1,255 @@ +# Testing the New Contributor System + +This guide helps you test and verify that the new conflict-free contributor system is working correctly. + +## For New Contributors: How to Test Your Contribution + +### 0. Test Locally First (Recommended!) + +Before submitting your PR, you can test your contributor file locally: + +```bash +# Quick preview - shows exactly how your profile will look +npm run contributors:preview your-github-username + +# Full validation - checks for any errors +npm run contributors:validate +``` + +**Example:** +```bash +# If your GitHub username is "johndoe" +npm run contributors:preview johndoe +``` + +This will show you: +- โœ… Validation results +- ๐ŸŽจ Preview of your profile +- ๐Ÿ“ฑ Exact HTML that will appear in README +- ๐Ÿท๏ธ Your contribution icons + +### 1. After Creating Your PR + +When you submit your PR with your `contributors/username.json` file, you can test several things: + +#### โœ… **Immediate Validation (Before Merge)** +Your PR will automatically trigger validation checks. Look for: + +1. **Green checkmarks** in your PR - this means validation passed +2. **Automated comment** welcoming you to the project +3. **No merge conflicts** reported (this should never happen with the new system!) + +#### โœ… **After Your PR is Merged** +Once a maintainer merges your PR, watch for these automatic actions: + +1. **Within 1-2 minutes**: A GitHub Action will run +2. **Within 5 minutes**: The README should update with your profile +3. **Automated welcome comment** on your merged PR + +### 2. How to Verify You're in the README + +#### Option A: Check the Live README +1. Go to the [main repository page](../../) +2. Scroll down to the "Contributors" section +3. Look for your profile picture and name +4. Your profile should appear in the contributor table + +#### Option B: Check the Badge Count +1. Look at the contributors badge: ![Contributors](https://img.shields.io/badge/all_contributors-310-orange.svg) +2. The number should have increased by 1 after your contribution +3. Click the badge to jump to the contributors section + +#### Option C: Search for Your Username +1. Press `Ctrl+F` (or `Cmd+F` on Mac) on the README page +2. Search for your GitHub username +3. You should find your profile in the contributors table + +### 3. What Your Profile Should Look Like + +Your contributor entry will appear like this: + +```html + + + Your Name +
+ Your Name +
+
+ ๐Ÿ’ป + ๐Ÿ“– + + +``` + +## For Maintainers: How to Test the System + +### 1. Test with a Sample Contributor + +Create a test contributor to verify the automation: + +```bash +# 1. Create a test contributor file +cat > contributors/test-user-$(date +%s).json << 'EOF' +{ + "name": "Test User", + "github": "test-user-123", + "profile": "https://example.com", + "contributions": ["code", "doc"] +} +EOF + +# 2. Commit and push +git add contributors/test-user-*.json +git commit -m "test: add test contributor to verify automation" +git push origin main + +# 3. Watch the GitHub Actions tab for the workflow to run + +# 4. Check that README was updated automatically + +# 5. Clean up the test file +git rm contributors/test-user-*.json +git commit -m "test: remove test contributor" +git push origin main +``` + +### 2. Monitor the GitHub Actions + +1. **Go to the Actions tab** in your repository +2. **Look for "Update Contributors" workflow** runs +3. **Check the logs** for any errors or issues +4. **Verify the README commit** was created automatically + +### 3. Test Validation + +```bash +# Test with invalid JSON +echo '{ invalid json }' > contributors/invalid-test.json +git add contributors/invalid-test.json +git commit -m "test: invalid contributor file" +git push + +# This should fail validation - check the Actions tab +# Then clean up: +git rm contributors/invalid-test.json +git commit -m "test: remove invalid file" +git push +``` + +## Troubleshooting Common Issues + +### โŒ "My profile isn't showing up" + +**Possible causes:** +1. **GitHub Action still running** - check the Actions tab, wait 5-10 minutes +2. **Validation failed** - check your JSON file format +3. **Wrong filename** - must be `your-exact-github-username.json` +4. **Missing required fields** - ensure you have `name`, `github`, and `contributions` + +**How to fix:** +```bash +# Validate your JSON file +python3 scripts/validate-contributor.py + +# Check if your username matches the filename +# File: contributors/johndoe.json +# Content: "github": "johndoe" โ† must match! +``` + +### โŒ "GitHub Action failed" + +**Check these:** +1. **Actions tab** for error details +2. **JSON syntax** - use a JSON validator online +3. **Required fields** - name, github, contributions must be present +4. **Username format** - only letters, numbers, and hyphens + +### โŒ "Badge count didn't increase" + +This usually means: +1. **Action is still running** - wait a few more minutes +2. **Validation failed** - check the Actions logs +3. **Duplicate contributor** - username already exists + +## Testing Checklist + +### For Contributors โœ… +- [ ] My PR has green checkmarks (validation passed) +- [ ] I received a welcome comment on my PR +- [ ] My PR was merged without conflicts +- [ ] My profile appears in the README within 10 minutes +- [ ] The contributors badge count increased by 1 +- [ ] I can find my username by searching the README + +### For Maintainers โœ… +- [ ] GitHub Actions run automatically on contributor file changes +- [ ] Validation catches invalid JSON files +- [ ] README updates automatically after merge +- [ ] Welcome comments are posted on successful contributions +- [ ] Multiple simultaneous PRs don't cause conflicts +- [ ] Old contributor data is preserved correctly + +## Performance Testing + +### Stress Test: Multiple Simultaneous Contributors + +To test the conflict-free nature: + +1. **Create 5+ test contributor files** simultaneously +2. **Submit them in separate PRs** at the same time +3. **Merge them quickly** one after another +4. **Verify no conflicts occur** and all are processed correctly + +```bash +# Example: Create multiple test files +for i in {1..5}; do + cat > contributors/stress-test-$i.json << EOF +{ + "name": "Stress Test User $i", + "github": "stress-test-$i", + "contributions": ["code"] +} +EOF +done +``` + +## Expected Behavior + +### โœ… **What Should Happen** +1. **PR validation** runs automatically +2. **Welcome comment** appears on valid PRs +3. **Merge happens** without conflicts +4. **GitHub Action runs** within 2 minutes of merge +5. **README updates** with new contributor +6. **Success comment** posted on merged PR +7. **Badge count increases** by 1 + +### โฑ๏ธ **Timing Expectations** +- **Validation**: Instant (on PR creation/update) +- **Merge**: Manual (when maintainer approves) +- **Action trigger**: 30 seconds after merge +- **README update**: 2-5 minutes after merge +- **Badge update**: Immediate with README update + +## Getting Help + +If testing reveals issues: + +1. **Check GitHub Actions logs** first +2. **Validate your JSON** using the validation script +3. **Ask in Discussions** with specific error details +4. **Create an issue** if you find a bug in the system + +## Success Metrics + +The system is working correctly when: +- โœ… **Zero merge conflicts** on contributor PRs +- โœ… **100% automation** - no manual README editing needed +- โœ… **Fast processing** - updates within 5 minutes +- โœ… **Perfect validation** - catches errors before merge +- โœ… **Beginner friendly** - simple JSON file creation + +--- + +**Ready to test?** Follow the [docs/guides/contributor-guide.md](docs/guides/contributor-guide.md) instructions to add yourself and see the magic happen! โœจ diff --git a/docs/guides/contributor-guide.md b/docs/guides/contributor-guide.md new file mode 100644 index 0000000..38f91c3 --- /dev/null +++ b/docs/guides/contributor-guide.md @@ -0,0 +1,114 @@ +# Contributors Directory + +Welcome to the guestbook contributors directory! ๐ŸŽ‰ + +## How to Add Yourself as a Contributor + +Instead of editing the main README.md file (which causes merge conflicts), you'll add yourself by creating your own contributor file. + +### Step-by-Step Instructions + +1. **Create your contributor file** + - In this `contributors/` directory, create a new file named `your-github-username.json` + - Replace `your-github-username` with your actual GitHub username (lowercase) + +2. **Add your information** + Copy this template and fill in your details: + + ```json + { + "name": "Your Full Name", + "github": "your-github-username", + "profile": "https://your-website.com", + "contributions": ["code", "doc", "ideas"] + } + ``` + +3. **Available contribution types** + You can include any of these contribution types in your `contributions` array: + - `"code"` - Code contributions + - `"doc"` - Documentation + - `"ideas"` - Ideas and planning + - `"bug"` - Bug reports + - `"tutorial"` - Tutorials + - `"design"` - Design + - `"review"` - Code reviews + - `"test"` - Testing + - `"blog"` - Blog posts + - `"translation"` - Translations + - `"question"` - Answering questions + - `"maintenance"` - Maintenance + - `"infra"` - Infrastructure + - `"research"` - Research + - `"talk"` - Talks/presentations + - `"video"` - Videos + - `"audio"` - Audio/podcasts + - `"content"` - Content creation + - `"data"` - Data contributions + - `"example"` - Examples + - `"tool"` - Tools + - `"plugin"` - Plugin/utility libraries + - `"platform"` - Packaging/porting + - `"security"` - Security + - `"business"` - Business development + - `"financial"` - Financial support + - `"fundingFinding"` - Funding finding + - `"eventOrganizing"` - Event organizing + - `"projectManagement"` - Project management + - `"promotion"` - Promotion + - `"mentoring"` - Mentoring + - `"userTesting"` - User testing + - `"a11y"` - Accessibility + +4. **Example file** + If your GitHub username is `johndoe`, create `contributors/johndoe.json`: + + ```json + { + "name": "John Doe", + "github": "johndoe", + "profile": "https://johndoe.dev", + "contributions": ["code", "doc", "tutorial"] + } + ``` + +5. **Test locally (optional)** + Want to see how your contribution will look before submitting? You have two options: + + **Option A: Quick Preview (Recommended)** + ```bash + # Preview how your profile will appear (safe, no file changes) + npm run contributors:preview your-github-username + ``` + + **Option B: Full Test (Advanced)** + ```bash + # Validate your JSON file + npm run contributors:validate + + # Full test with temporary README generation + npm run contributors:test your-github-username + ``` + + Both will show you exactly how your profile will appear in the README! + +6. **Submit your pull request** + - Your PR should only add ONE file: your `contributors/your-username.json` file + - Title your PR: "Add [Your Name] as a contributor" + - No need to edit any other files! + +7. **Automatic processing** + Once your PR is merged, a GitHub Action will automatically: + - Add you to the all-contributors system + - Update the main README.md with your information + - You'll appear in the contributors table! + +8. **Verify it worked** + Want to confirm your contribution was successful? See: [testing-your-contribution.md](testing-your-contribution.md) + + +## Need Help? + +- Check out existing contributor files for examples +- Ask questions in [GitHub Discussions](../../discussions) +- Review the [Contributing Guidelines](../../CONTRIBUTING.md) diff --git a/docs/guides/testing-your-contribution.md b/docs/guides/testing-your-contribution.md new file mode 100644 index 0000000..c098eec --- /dev/null +++ b/docs/guides/testing-your-contribution.md @@ -0,0 +1,111 @@ +# ๐Ÿงช Quick Test: Did My Contribution Work? + +Follow these simple steps to verify your contribution was successful! + +## Step 1: Check Your PR Status โœ… + +After submitting your PR, look for: +- ๐ŸŸข **Green checkmarks** next to your PR (means validation passed) +- ๐Ÿ’ฌ **Welcome comment** from the bot +- ๐Ÿšซ **No merge conflicts** (there shouldn't be any!) + +## Step 2: After Your PR is Merged ๐ŸŽ‰ + +### Immediate (1-2 minutes) +1. **Look for the GitHub Action**: + - Go to the [Actions tab](../../actions) + - You should see "Update Contributors" running or completed + - Green checkmark = success! โœ… + +### Within 5 minutes +2. **Check if you're in the README**: + - Go back to the [main page](../../) + - Scroll down to "Contributors" section + - **Search for your name**: Press `Ctrl+F` (or `Cmd+F`) and type your GitHub username + - You should see your profile picture! ๐Ÿ–ผ๏ธ + +3. **Check the badge count**: + - Look for this badge: ![Contributors](https://img.shields.io/badge/all_contributors-310-orange.svg) + - The number should have increased by 1 + - Click the badge to jump directly to contributors section + +## Step 3: Celebrate! ๐ŸŽ‰ + +If you see your profile in the contributors section, congratulations! You've successfully: +- โœ… Made your first open source contribution +- โœ… Used the new conflict-free system +- โœ… Helped test and improve the process +- โœ… Joined the open source community! + +## What Your Profile Looks Like + +Your entry will appear something like this: + +``` +[Your Profile Picture] +Your Name +๐Ÿ’ป ๐Ÿ“– ๐ŸŽจ โ† Contribution type icons +``` + +The icons represent your contribution types: +- ๐Ÿ’ป = Code +- ๐Ÿ“– = Documentation +- ๐ŸŽจ = Design +- ๐Ÿ› = Bug reports +- โœ… = Tutorials +- ๐Ÿ’ก = Ideas +- And many more! + +## โŒ Troubleshooting: "I Don't See My Profile" + +### Check These First: +1. **Was your PR merged?** (Look for purple "Merged" badge) +2. **Did the GitHub Action run?** (Check [Actions tab](../../actions)) +3. **Any validation errors?** (Look at the Action logs) + +### Common Issues: + +**๐Ÿ”ง JSON Format Error** +```json +โŒ Wrong: { name: "John Doe" } // Missing quotes +โœ… Right: { "name": "John Doe" } // Proper JSON +``` + +**๐Ÿ”ง Filename Mismatch** +``` +โŒ Wrong: contributors/john.json + "github": "johndoe" +โœ… Right: contributors/johndoe.json + "github": "johndoe" +``` + +**๐Ÿ”ง Missing Required Fields** +```json +โŒ Wrong: { "name": "John" } +โœ… Right: { + "name": "John Doe", + "github": "johndoe", + "contributions": ["code"] +} +``` + +### Still Need Help? + +1. **Check the validation**: Run this in your terminal: + ```bash + python3 scripts/validate-contributor.py + ``` + +2. **Ask for help**: + - ๐Ÿ’ฌ [GitHub Discussions](../../discussions) + - ๐Ÿ› [Create an Issue](../../issues/new) + - ๐Ÿ“– [Read the detailed guide](contributor-guide.md) + +## Next Steps from the Course + +After your profile appears: +1. ๐ŸŒŸ **Create a highlight** of your contribution on [OpenSauced](https://app.opensauced.pizza/feed) +2. ๐ŸŽ“ **Continue the course**: [The Secret Sauce](https://opensauced.pizza/learn/intro-to-oss/the-secret-sauce) +3. ๐Ÿ• **Make more contributions**: Check out [pizza-verse](https://github.com/OpenSource-Communities/pizza-verse) + +--- + +**๐ŸŽ‰ Welcome to the open source community!** Your first contribution is a big milestone - celebrate it! ๐Ÿš€ \ No newline at end of file diff --git a/package.json b/package.json index cae2775..a0abcb9 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,11 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "contributors:generate": "all-contributors generate", - "contributors:add": "all-contributors add" + "contributors:add": "all-contributors add", + "contributors:validate": "python3 scripts/validate-contributor.py", + "contributors:migrate": "./scripts/migrate-contributors.sh", + "contributors:test": "./scripts/test-locally.sh", + "contributors:preview": "python3 scripts/preview-contribution.py" }, "keywords": [], "author": "", diff --git a/scripts/migrate-contributors.sh b/scripts/migrate-contributors.sh new file mode 100755 index 0000000..d96ab78 --- /dev/null +++ b/scripts/migrate-contributors.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +# Script to migrate existing contributors to the new JSON file format +# This reads the current .all-contributorsrc and creates individual JSON files + +echo "Migrating existing contributors to individual JSON files..." + +# Create contributors directory if it doesn't exist +mkdir -p contributors + +# Check if .all-contributorsrc exists +if [ ! -f ".all-contributorsrc" ]; then + echo "No existing .all-contributorsrc file found" + exit 1 +fi + +# Check if Python is available for JSON parsing +if ! command -v python3 &> /dev/null; then + echo "Python3 is required for this script" + exit 1 +fi + +# Python script to parse contributors and create JSON files +python3 << 'EOF' +import json +import os + +# Read the .all-contributorsrc file +try: + with open('.all-contributorsrc', 'r') as f: + data = json.load(f) +except FileNotFoundError: + print("No .all-contributorsrc file found") + exit(1) +except json.JSONDecodeError: + print("Error: Invalid JSON in .all-contributorsrc") + exit(1) + +# Create contributors directory +os.makedirs('contributors', exist_ok=True) + +# Process each contributor +contributors = data.get('contributors', []) +if not contributors: + print("No contributors found in .all-contributorsrc") + exit(0) + +for contributor in contributors: + login = contributor.get('login') + name = contributor.get('name') + profile = contributor.get('profile') + contributions = contributor.get('contributions', []) + + if not login or not name: + print(f"Skipping contributor with missing login or name: {contributor}") + continue + + # Create the contributor data + contributor_data = { + "name": name, + "github": login, + "contributions": contributions + } + + # Add profile if it exists + if profile: + contributor_data["profile"] = profile + + # Write to JSON file + filename = f"contributors/{login}.json" + try: + with open(filename, 'w') as f: + json.dump(contributor_data, f, indent=2, ensure_ascii=False) + print(f"Created {filename}") + except Exception as e: + print(f"Error creating {filename}: {e}") + +print(f"Migration complete! Created {len(contributors)} contributor files.") +EOF + +echo "" +echo "Migration summary:" +echo "- Individual JSON files created in contributors/ directory" +echo "- Original .all-contributorsrc preserved as backup" +echo "- Run 'git add contributors/' to stage the new files" +echo "- The GitHub Action will automatically update the README after merge" \ No newline at end of file diff --git a/scripts/preview-contribution.py b/scripts/preview-contribution.py new file mode 100755 index 0000000..b287b16 --- /dev/null +++ b/scripts/preview-contribution.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +""" +Simple preview script for contributor JSON files +Shows how the contributor will appear without modifying any files +""" + +import json +import sys +import os +from pathlib import Path + +def preview_contributor(username): + """Preview how a contributor will appear in the README""" + + contributor_file = Path(f"contributors/{username}.json") + + if not contributor_file.exists(): + print(f"โŒ File not found: {contributor_file}") + print(f"๐Ÿ’ก Create {contributor_file} first!") + return False + + try: + with open(contributor_file, 'r') as f: + data = json.load(f) + except json.JSONDecodeError as e: + print(f"โŒ Invalid JSON in {contributor_file}: {e}") + return False + except Exception as e: + print(f"โŒ Error reading {contributor_file}: {e}") + return False + + # Validate required fields + required = ['name', 'github', 'contributions'] + missing = [field for field in required if field not in data or not data[field]] + + if missing: + print(f"โŒ Missing required fields: {missing}") + return False + + # Check username match + if data['github'] != username: + print(f"โŒ Username mismatch:") + print(f" Filename: {username}.json") + print(f" JSON github field: {data['github']}") + print(f" These must match!") + return False + + print("โœ… Contributor file validation passed!") + print() + + # Show preview + name = data['name'] + github = data['github'] + profile = data.get('profile', f'https://github.com/{github}') + contributions = data['contributions'] + + print("๐ŸŽจ Preview of your contributor profile:") + print("=" * 50) + print(f"๐Ÿ‘ค Name: {name}") + print(f"๐Ÿ”— Profile: {profile}") + print(f"๐Ÿ“ท Avatar: https://github.com/{github}.png") + print(f"๐ŸŽฏ Contributions: {', '.join(contributions)}") + print() + + # Show contribution icons + contribution_icons = { + 'a11y': 'โ™ฟ๏ธ', 'audio': '๐Ÿ”Š', 'blog': '๐Ÿ“', 'bug': '๐Ÿ›', + 'business': '๐Ÿ’ผ', 'code': '๐Ÿ’ป', 'content': '๐Ÿ–‹', 'data': '๐Ÿ”ฃ', + 'design': '๐ŸŽจ', 'doc': '๐Ÿ“–', 'eventOrganizing': '๐Ÿ“‹', 'example': '๐Ÿ’ก', + 'financial': '๐Ÿ’ต', 'fundingFinding': '๐Ÿ”', 'ideas': '๐Ÿค”', 'infra': '๐Ÿš‡', + 'maintenance': '๐Ÿšง', 'mentoring': '๐Ÿง‘โ€๐Ÿซ', 'platform': '๐Ÿ“ฆ', 'plugin': '๐Ÿ”Œ', + 'projectManagement': '๐Ÿ“†', 'promotion': '๐Ÿ“ฃ', 'question': '๐Ÿ’ฌ', 'research': '๐Ÿ”ฌ', + 'review': '๐Ÿ‘€', 'security': '๐Ÿ›ก๏ธ', 'talk': '๐Ÿ“ข', 'test': 'โš ๏ธ', + 'tool': '๐Ÿ”ง', 'translation': '๐ŸŒ', 'tutorial': 'โœ…', 'userTesting': '๐Ÿ““', + 'video': '๐Ÿ“น' + } + + print("๐Ÿท๏ธ Your contribution icons:") + for contrib in contributions: + icon = contribution_icons.get(contrib, 'โ“') + print(f" {icon} {contrib}") + + print() + print("๐Ÿ“ฑ How it will look in the README:") + print("=" * 50) + + # Generate HTML preview (simplified) + icons_html = ' '.join([f'{contribution_icons.get(contrib, "โ“")}' + for contrib in contributions]) + + html_preview = f''' + + + {name} +
+ {name} +
+
+ {icons_html} +''' + + print(html_preview) + print() + print("=" * 50) + print("โœ… Your contribution looks great!") + print() + print("๐Ÿš€ Next steps:") + print(f" 1. git add {contributor_file}") + print(f" 2. git commit -m 'Add {name} as a contributor'") + print(f" 3. git push origin your-branch-name") + print(f" 4. Create your pull request!") + print() + print("๐Ÿ’ก After your PR is merged, this exact profile will appear in the README automatically!") + + return True + +def main(): + if len(sys.argv) != 2: + print("Usage: python3 scripts/preview-contribution.py your-username") + print("Example: python3 scripts/preview-contribution.py johndoe") + sys.exit(1) + + username = sys.argv[1] + success = preview_contributor(username) + + if not success: + print() + print("๐Ÿ”ง Need help?") + print(" - Check the template in docs/guides/contributor-guide.md") + print(" - Validate JSON syntax at https://jsonlint.com/") + print(" - Ask questions in GitHub Discussions") + sys.exit(1) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/scripts/test-locally.sh b/scripts/test-locally.sh new file mode 100755 index 0000000..7d1a989 --- /dev/null +++ b/scripts/test-locally.sh @@ -0,0 +1,178 @@ +#!/bin/bash + +# Local testing script for contributors +# This allows contributors to test their JSON file and see how it will appear in the README + +echo "๐Ÿงช Testing your contributor file locally..." + +# Check if contributor file is provided +if [ $# -eq 0 ]; then + echo "Usage: ./scripts/test-locally.sh your-username" + echo "Example: ./scripts/test-locally.sh johndoe" + exit 1 +fi + +USERNAME=$1 +CONTRIBUTOR_FILE="contributors/${USERNAME}.json" + +# Check if the contributor file exists +if [ ! -f "$CONTRIBUTOR_FILE" ]; then + echo "โŒ File not found: $CONTRIBUTOR_FILE" + echo "๐Ÿ’ก Make sure you've created your contributor file first!" + exit 1 +fi + +echo "๐Ÿ“ Found contributor file: $CONTRIBUTOR_FILE" + +# Validate the JSON file +echo "๐Ÿ” Validating JSON format..." +if ! python3 -c "import json; json.load(open('$CONTRIBUTOR_FILE'))" 2>/dev/null; then + echo "โŒ Invalid JSON format in $CONTRIBUTOR_FILE" + echo "๐Ÿ’ก Check your JSON syntax - use quotes around all strings!" + exit 1 +fi + +echo "โœ… JSON format is valid" + +# Validate required fields +echo "๐Ÿ” Checking required fields..." +python3 << EOF +import json +import sys + +with open('$CONTRIBUTOR_FILE', 'r') as f: + data = json.load(f) + +errors = [] +required_fields = ['name', 'github', 'contributions'] + +for field in required_fields: + if field not in data: + errors.append(f"Missing field: {field}") + elif not data[field]: + errors.append(f"Empty field: {field}") + +if data.get('github') != '$USERNAME': + errors.append(f"GitHub username '{data.get('github')}' doesn't match filename '$USERNAME.json'") + +if not isinstance(data.get('contributions', []), list): + errors.append("contributions must be an array") +elif len(data.get('contributions', [])) == 0: + errors.append("contributions array is empty") + +if errors: + print("โŒ Validation errors:") + for error in errors: + print(f" - {error}") + sys.exit(1) +else: + print("โœ… All required fields present and valid") + print(f"๐Ÿ“ Name: {data['name']}") + print(f"๐Ÿ‘ค GitHub: @{data['github']}") + if 'profile' in data and data['profile']: + print(f"๐Ÿ”— Profile: {data['profile']}") + print(f"๐ŸŽฏ Contributions: {', '.join(data['contributions'])}") +EOF + +if [ $? -ne 0 ]; then + exit 1 +fi + +# Create a backup of current README +echo "๐Ÿ’พ Creating backup of current README..." +cp README.md README.md.backup + +# Create a test all-contributors config +echo "โš™๏ธ Setting up test environment..." +cp .all-contributorsrc .all-contributorsrc.backup + +# Add just this contributor to test +echo "๐Ÿ”„ Testing contributor addition..." +python3 << EOF +import json + +# Read contributor data +with open('$CONTRIBUTOR_FILE', 'r') as f: + contributor_data = json.load(f) + +# Create minimal all-contributors config for testing +config = { + "projectName": "guestbook", + "projectOwner": "OpenSource-Community", + "repoType": "github", + "repoHost": "https://github.com", + "files": ["README.md"], + "imageSize": 100, + "commit": false, + "commitConvention": "angular", + "contributors": [ + { + "login": contributor_data["github"], + "name": contributor_data["name"], + "avatar_url": f"https://github.com/{contributor_data['github']}.png", + "profile": contributor_data.get("profile", f"https://github.com/{contributor_data['github']}"), + "contributions": contributor_data["contributions"] + } + ] +} + +# Write test config +with open('.all-contributorsrc.test', 'w') as f: + json.dump(config, f, indent=2) + +print("โœ… Test configuration created") +EOF + +# Copy test config over main config temporarily +cp .all-contributorsrc.test .all-contributorsrc + +# Generate test README section +echo "๐ŸŽจ Generating test preview..." +npx all-contributors generate + +# Show the contributor section +echo "" +echo "๐ŸŽ‰ SUCCESS! Here's how your contribution will appear:" +echo "==================================================" +echo "" + +# Extract just the contributor table for preview +python3 << EOF +import re + +with open('README.md', 'r') as f: + content = f.read() + +# Find the contributors section +start_marker = "" + +start = content.find(start_marker) +end = content.find(end_marker) + +if start != -1 and end != -1: + contributors_section = content[start:end + len(end_marker)] + print(contributors_section) +else: + print("Could not extract contributors section") +EOF + +echo "" +echo "==================================================" +echo "" + +# Restore original files +echo "๐Ÿ”„ Restoring original files..." +mv README.md.backup README.md +mv .all-contributorsrc.backup .all-contributorsrc +rm -f .all-contributorsrc.test + +echo "โœ… Test complete! Your contributor file looks good." +echo "" +echo "๐Ÿš€ Next steps:" +echo " 1. Commit your file: git add $CONTRIBUTOR_FILE" +echo " 2. Create your PR: git commit -m 'Add $USERNAME as a contributor'" +echo " 3. Submit and wait for merge!" +echo " 4. Check the live README in 5 minutes after merge" +echo "" +echo "๐Ÿ’ก Remember: The actual README will be updated automatically after your PR is merged!" \ No newline at end of file diff --git a/scripts/validate-contributor.py b/scripts/validate-contributor.py new file mode 100755 index 0000000..24fe345 --- /dev/null +++ b/scripts/validate-contributor.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 +""" +Validation script for contributor JSON files +This script validates that contributor JSON files follow the expected format +""" + +import json +import os +import sys +import re +from pathlib import Path + +# Valid contribution types based on all-contributors specification +VALID_CONTRIBUTIONS = { + "a11y", "audio", "blog", "bug", "business", "code", "content", "data", + "design", "doc", "eventOrganizing", "example", "financial", "fundingFinding", + "ideas", "infra", "maintenance", "mentoring", "platform", "plugin", + "projectManagement", "promotion", "question", "research", "review", + "security", "talk", "test", "tool", "translation", "tutorial", "userTesting", + "video" +} + +def validate_json_file(filepath): + """Validate a single contributor JSON file""" + errors = [] + warnings = [] + + try: + with open(filepath, 'r', encoding='utf-8') as f: + data = json.load(f) + except json.JSONDecodeError as e: + return [f"Invalid JSON: {e}"], [] + except Exception as e: + return [f"Error reading file: {e}"], [] + + # Check required fields + required_fields = ['name', 'github', 'contributions'] + for field in required_fields: + if field not in data: + errors.append(f"Missing required field: {field}") + elif not data[field]: + errors.append(f"Empty required field: {field}") + + # Validate name + if 'name' in data: + if not isinstance(data['name'], str): + errors.append("Field 'name' must be a string") + elif len(data['name'].strip()) == 0: + errors.append("Field 'name' cannot be empty") + + # Validate github username + if 'github' in data: + github = data['github'] + if not isinstance(github, str): + errors.append("Field 'github' must be a string") + elif not re.match(r'^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$', github): + errors.append(f"Invalid GitHub username format: {github}") + else: + # Check if filename matches GitHub username + expected_filename = f"{github}.json" + actual_filename = os.path.basename(filepath) + if actual_filename != expected_filename: + warnings.append(f"Filename '{actual_filename}' doesn't match GitHub username '{github}' (should be '{expected_filename}')") + + # Validate contributions + if 'contributions' in data: + contributions = data['contributions'] + if not isinstance(contributions, list): + errors.append("Field 'contributions' must be an array") + elif len(contributions) == 0: + warnings.append("Field 'contributions' is empty") + else: + for contrib in contributions: + if not isinstance(contrib, str): + errors.append(f"Contribution type must be a string: {contrib}") + elif contrib not in VALID_CONTRIBUTIONS: + warnings.append(f"Unknown contribution type: {contrib}") + + # Validate optional profile field + if 'profile' in data: + profile = data['profile'] + if not isinstance(profile, str): + errors.append("Field 'profile' must be a string") + elif profile and not re.match(r'^https?://', profile): + warnings.append(f"Profile URL should start with http:// or https://: {profile}") + + # Check for unexpected fields + expected_fields = {'name', 'github', 'contributions', 'profile'} + extra_fields = set(data.keys()) - expected_fields + if extra_fields: + warnings.append(f"Unexpected fields: {', '.join(extra_fields)}") + + return errors, warnings + +def main(): + """Main validation function""" + contributors_dir = Path("contributors") + + if not contributors_dir.exists(): + print("โŒ Contributors directory not found") + sys.exit(1) + + json_files = list(contributors_dir.glob("*.json")) + if not json_files: + print("โŒ No JSON files found in contributors directory") + sys.exit(1) + + total_errors = 0 + total_warnings = 0 + + print(f"๐Ÿ” Validating {len(json_files)} contributor files...\n") + + for filepath in sorted(json_files): + errors, warnings = validate_json_file(filepath) + + if errors or warnings: + print(f"๐Ÿ“ {filepath.name}:") + + for error in errors: + print(f" โŒ {error}") + total_errors += 1 + + for warning in warnings: + print(f" โš ๏ธ {warning}") + total_warnings += 1 + + print() + else: + print(f"โœ… {filepath.name}") + + print(f"\n๐Ÿ“Š Validation Summary:") + print(f" Files checked: {len(json_files)}") + print(f" Errors: {total_errors}") + print(f" Warnings: {total_warnings}") + + if total_errors > 0: + print("\nโŒ Validation failed! Please fix the errors above.") + sys.exit(1) + elif total_warnings > 0: + print("\nโš ๏ธ Validation passed with warnings. Consider fixing the warnings above.") + sys.exit(0) + else: + print("\nโœ… All files are valid!") + sys.exit(0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/scripts/verify-migration.sh b/scripts/verify-migration.sh new file mode 100755 index 0000000..9689113 --- /dev/null +++ b/scripts/verify-migration.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +echo "๐Ÿ” Verifying migration completion..." + +# Count contributor files +json_files=$(find contributors/ -name "*.json" ! -name "example-contributor.json" | wc -l) +echo "๐Ÿ“ JSON files: $json_files" + +# Count contributors in README +readme_contributors=$(grep -c "align=\"center\"" README.md) +readme_contributors=$((readme_contributors - 1)) # Subtract header row +echo "๐Ÿ“„ README contributors: $readme_contributors" + +# Check badge count +badge_count=$(grep -o "all_contributors-[0-9]*" README.md | head -1 | cut -d'-' -f2) +echo "๐Ÿท๏ธ Badge count: $badge_count" + +# Verify README is complete +if grep -q "ALL-CONTRIBUTORS-LIST:END" README.md; then + echo "โœ… README properly closed" +else + echo "โŒ README missing closing tags" +fi + +# Check for validation errors +echo "๐Ÿ” Running validation..." +python3 scripts/validate-contributor.py > /tmp/validation.log 2>&1 +if [ $? -eq 0 ]; then + echo "โœ… All contributor files valid" +else + echo "โŒ Validation errors found:" + cat /tmp/validation.log +fi + +# Summary +echo "" +echo "๐Ÿ“Š Migration Summary:" +echo " Expected: 310 contributors" +echo " JSON files: $json_files" +echo " README entries: $readme_contributors" +echo " Badge count: $badge_count" + +if [ "$json_files" -eq 310 ] && [ "$readme_contributors" -eq 310 ] && [ "$badge_count" -eq 310 ]; then + echo "โœ… Migration successful! All counts match." +else + echo "โš ๏ธ Count mismatch detected. Review needed." +fi + +echo "" +echo "๐Ÿš€ Next steps:" +echo "1. Commit and push all changes" +echo "2. Test the GitHub Action with a sample contributor" +echo "3. Update course materials to reference new process" +echo "4. Pin announcement issue for contributors" \ No newline at end of file From 6d02b42b0360888313d2063ac6c44bcd77608455 Mon Sep 17 00:00:00 2001 From: BekahHW <34313413+BekahHW@users.noreply.github.com> Date: Mon, 15 Sep 2025 13:56:33 -0400 Subject: [PATCH 2/6] Update .github/PULL_REQUEST_TEMPLATE.md Co-authored-by: Ayu Adiati <45172775+adiati98@users.noreply.github.com> --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index cafef70..dc7f5f7 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -16,7 +16,7 @@ ### Checklist for Adding Yourself - [ ] I created a file named `contributors/[my-github-username].json` -- [ ] I filled in all required fields: `name`, `github`, `contributions` +- [ ] I filled in all required fields: `name`, `github`, `contributions`, `profile` - [ ] I only added ONE file (my contributor JSON file) - [ ] My JSON file is valid (no syntax errors) - [ ] I'm completing the [Intro to Open Source course](https://opensauced.pizza/learn/intro-to-oss/) From e03b56595733fcb077a4d32cb92c501f12f7317c Mon Sep 17 00:00:00 2001 From: BekahHW <34313413+BekahHW@users.noreply.github.com> Date: Mon, 15 Sep 2025 13:57:42 -0400 Subject: [PATCH 3/6] Update .github/workflows/validate-pr.yml Co-authored-by: Ayu Adiati <45172775+adiati98@users.noreply.github.com> --- .github/workflows/validate-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-pr.yml b/.github/workflows/validate-pr.yml index 9957b69..4aabf31 100644 --- a/.github/workflows/validate-pr.yml +++ b/.github/workflows/validate-pr.yml @@ -60,7 +60,7 @@ try: with open('$file', 'r') as f: data = json.load(f) - required_fields = ['name', 'github', 'contributions'] + required_fields = ['name', 'github', 'contributions', 'profile'] missing_fields = [field for field in required_fields if field not in data or not data[field]] if missing_fields: From 114bb974324bf77a8902806029e1198a054ccacb Mon Sep 17 00:00:00 2001 From: BekahHW Date: Tue, 16 Sep 2025 10:30:48 -0400 Subject: [PATCH 4/6] Add node.js testing and address some comments --- .github/workflows/update-contributors.yml | 11 ++++- README.md | 15 ++++-- docs/guides/contributor-guide.md | 57 +++++++++++++++++------ package.json | 6 +-- scripts/preview-contribution.py | 2 +- scripts/test-locally.sh | 8 ++-- 6 files changed, 70 insertions(+), 29 deletions(-) diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml index 94b77ad..f7540c0 100644 --- a/.github/workflows/update-contributors.yml +++ b/.github/workflows/update-contributors.yml @@ -62,13 +62,18 @@ jobs: exit 0 fi + # Count total files to process + total_files=$(ls -1 contributors/*.json 2>/dev/null | grep -v -E '(example-contributor\.json|\.gitkeep|README\.md)' | wc -l) + echo "Found $total_files contributor files to process" + # Process each JSON file + processed=0 for file in contributors/*.json; do if [ -f "$file" ]; then filename=$(basename "$file") # Skip example and template files - if [[ "$filename" == "example-contributor.json" ]] || [[ "$filename" == ".gitkeep" ]]; then + if [[ "$filename" == "example-contributor.json" ]] || [[ "$filename" == ".gitkeep" ]] || [[ "$filename" == "README.md" ]]; then echo "Skipping template file: $filename" continue fi @@ -102,8 +107,12 @@ jobs: else npx all-contributors add "$github_username" "$contributions" --name "$name" fi + + processed=$((processed + 1)) fi done + + echo "โœ… Processed $processed contributor files" - name: Generate contributors section run: | diff --git a/README.md b/README.md index 9c0c55a..181eda9 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,13 @@ This guestbook is a place for people who have taken the [Intro to Open Source co Instead of editing this README directly, you now add yourself by creating a single JSON file. This prevents merge conflicts when multiple people contribute simultaneously. ### Quick Start -1. Go to the [`contributors/`](contributors/) directory -2. Create a file named `your-github-username.json` -3. Fill it with your information (see template below) -4. Submit your PR with just that one file! +1. Fork and clone this repository +2. Run `npm install` to install dependencies +3. Go to the [`contributors/`](contributors/) directory +4. Create a file named `your-github-username.json` +5. Fill it with your information (see template below) +6. Test your contribution: `npm run contributors:preview your-github-username` +7. Submit your PR with just that one file! ### Template ```json @@ -26,6 +29,8 @@ Instead of editing this README directly, you now add yourself by creating a sing } ``` +**Note:** The `profile` field should be your personal website URL or your GitHub profile URL (https://github.com/your-username) + ๐Ÿ“– **For detailed instructions, see: [docs/guides/contributor-guide.md](docs/guides/contributor-guide.md)** > **Note**: The contributors table below is automatically updated when your PR is merged. No need to edit it manually! @@ -218,4 +223,4 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d ๐Ÿ…ฟ๏ธadi
๐Ÿ…ฟ๏ธadi

๐Ÿ› - JohnKagunda
JohnKagunda

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ› ๐Ÿ’ผ ๐Ÿ’ป JohnKagunda
JohnKagunda

๏ธ๏ธ๏ธ๏ธโ™ฟ๏ธ ๐Ÿ› Date: Tue, 16 Sep 2025 10:30:54 -0400 Subject: [PATCH 5/6] Add node.js testing and address some comments --- .github/workflows/validate-contributor.yml | 74 ++++++++ contributors/QUICK_TEST.md | 111 ++++++++++++ docs/TROUBLESHOOTING.md | 85 +++++++++ docs/guides/migration-to-js.md | 41 +++++ scripts/preview-contribution.js | 147 ++++++++++++++++ scripts/test-locally.js | 192 +++++++++++++++++++++ scripts/validate-contributor.js | 162 +++++++++++++++++ 7 files changed, 812 insertions(+) create mode 100644 .github/workflows/validate-contributor.yml create mode 100644 contributors/QUICK_TEST.md create mode 100644 docs/TROUBLESHOOTING.md create mode 100644 docs/guides/migration-to-js.md create mode 100755 scripts/preview-contribution.js create mode 100755 scripts/test-locally.js create mode 100755 scripts/validate-contributor.js diff --git a/.github/workflows/validate-contributor.yml b/.github/workflows/validate-contributor.yml new file mode 100644 index 0000000..898e245 --- /dev/null +++ b/.github/workflows/validate-contributor.yml @@ -0,0 +1,74 @@ +name: Validate Contributor + +on: + pull_request: + paths: + - 'contributors/*.json' + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - name: Checkout PR + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v39 + with: + files: | + contributors/*.json + + - name: Validate contributor files + if: steps.changed-files.outputs.any_changed == 'true' + run: | + echo "๐Ÿ” Validating contributor files..." + + # Install dependencies + npm install + + # Run validation + node scripts/validate-contributor.js + + # Check specific changed files + for file in ${{ steps.changed-files.outputs.all_changed_files }}; do + echo "Checking $file" + + if [[ "$file" == contributors/*.json ]]; then + filename=$(basename "$file") + username="${filename%.json}" + + # Run preview for the specific file + echo "Preview for $username:" + node scripts/preview-contribution.js "$username" + fi + done + + - name: Comment on PR + if: failure() + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'โŒ Your contributor file has validation errors. Please check the [action logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.\n\nCommon issues:\n- Username in filename must match the `github` field in JSON\n- All required fields must be present: `name`, `github`, `contributions`\n- Use valid contribution types\n\nNeed help? Check the [contributor guide](docs/guides/contributor-guide.md).' + }) + + - name: Success comment + if: success() && steps.changed-files.outputs.any_changed == 'true' + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'โœ… Your contributor file is valid! Once this PR is merged, you\'ll automatically appear in the contributors section.\n\nThank you for your contribution! ๐ŸŽ‰' + }) \ No newline at end of file diff --git a/contributors/QUICK_TEST.md b/contributors/QUICK_TEST.md new file mode 100644 index 0000000..da16c83 --- /dev/null +++ b/contributors/QUICK_TEST.md @@ -0,0 +1,111 @@ +S# ๐Ÿงช Quick Test: Did My Contribution Work? + +Follow these simple steps to verify your contribution was successful! + +## Step 1: Check Your PR Status โœ… + +After submitting your PR, look for: +- ๐ŸŸข **Green checkmarks** next to your PR (means validation passed) +- ๐Ÿ’ฌ **Welcome comment** from the bot +- ๐Ÿšซ **No merge conflicts** (there shouldn't be any!) + +## Step 2: After Your PR is Merged ๐ŸŽ‰ + +### Immediate (1-2 minutes) +1. **Look for the GitHub Action**: + - Go to the [Actions tab](../../actions) + - You should see "Update Contributors" running or completed + - Green checkmark = success! โœ… + +### Within 5 minutes +2. **Check if you're in the README**: + - Go back to the [main page](../../) + - Scroll down to "Contributors" section + - **Search for your name**: Press `Ctrl+F` (or `Cmd+F`) and type your GitHub username + - You should see your profile picture! ๐Ÿ–ผ๏ธ + +3. **Check the badge count**: + - Look for this badge: ![Contributors](https://img.shields.io/badge/all_contributors-310-orange.svg) + - The number should have increased by 1 + - Click the badge to jump directly to contributors section + +## Step 3: Celebrate! ๐ŸŽ‰ + +If you see your profile in the contributors section, congratulations! You've successfully: +- โœ… Made your first open source contribution +- โœ… Used the new conflict-free system +- โœ… Helped test and improve the process +- โœ… Joined the open source community! + +## What Your Profile Looks Like + +Your entry will appear something like this: + +``` +[Your Profile Picture] +Your Name +๐Ÿ’ป ๐Ÿ“– ๐ŸŽจ โ† Contribution type icons +``` + +The icons represent your contribution types: +- ๐Ÿ’ป = Code +- ๐Ÿ“– = Documentation +- ๐ŸŽจ = Design +- ๐Ÿ› = Bug reports +- โœ… = Tutorials +- ๐Ÿ’ก = Ideas +- And many more! + +## โŒ Troubleshooting: "I Don't See My Profile" + +### Check These First: +1. **Was your PR merged?** (Look for purple "Merged" badge) +2. **Did the GitHub Action run?** (Check [Actions tab](../../actions)) +3. **Any validation errors?** (Look at the Action logs) + +### Common Issues: + +**๐Ÿ”ง JSON Format Error** +```json +โŒ Wrong: { name: "John Doe" } // Missing quotes +โœ… Right: { "name": "John Doe" } // Proper JSON +``` + +**๐Ÿ”ง Filename Mismatch** +``` +โŒ Wrong: contributors/john.json + "github": "johndoe" +โœ… Right: contributors/johndoe.json + "github": "johndoe" +``` + +**๐Ÿ”ง Missing Required Fields** +```json +โŒ Wrong: { "name": "John" } +โœ… Right: { + "name": "John Doe", + "github": "johndoe", + "contributions": ["code"] +} +``` + +### Still Need Help? + +1. **Check the validation**: Run this in your terminal: + ```bash + python3 scripts/validate-contributor.py + ``` + +2. **Ask for help**: + - ๐Ÿ’ฌ [GitHub Discussions](../../discussions) + - ๐Ÿ› [Create an Issue](../../issues/new) + - ๐Ÿ“– [Read the detailed guide](README.md) + +## Next Steps from the Course + +After your profile appears: +1. ๐ŸŒŸ **Create a highlight** of your contribution on [OpenSauced](https://app.opensauced.pizza/feed) +2. ๐ŸŽ“ **Continue the course**: [The Secret Sauce](https://opensauced.pizza/learn/intro-to-oss/the-secret-sauce) +3. ๐Ÿ• **Make more contributions**: Check out [pizza-verse](https://github.com/OpenSource-Communities/pizza-verse) + +--- + +**๐ŸŽ‰ Welcome to the open source community!** Your first contribution is a big milestone - celebrate it! ๐Ÿš€ \ No newline at end of file diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md new file mode 100644 index 0000000..a3605a7 --- /dev/null +++ b/docs/TROUBLESHOOTING.md @@ -0,0 +1,85 @@ +# Troubleshooting Guide + +## Common Issues and Solutions + +### npm command not found +**Problem:** When running `npm install`, you get "command not found" + +**Solution:** You need to install Node.js: +- Download from [nodejs.org](https://nodejs.org/) +- Choose the LTS version +- After installation, restart your terminal + +### Permission denied when running scripts +**Problem:** Getting permission errors when running npm scripts + +**Solution:** The scripts need to be executable: +```bash +chmod +x scripts/*.sh +``` + +### JSON validation errors +**Problem:** Your contributor file shows as invalid + +**Common causes:** +1. **Missing comma:** Each line except the last needs a comma +2. **Wrong quotes:** Use double quotes (") not single quotes (') +3. **Username mismatch:** The filename must match the github field + +**Example of correct format:** +```json +{ + "name": "Jane Doe", + "github": "janedoe", + "profile": "https://github.com/janedoe", + "contributions": ["code", "doc"] +} +``` + +### Preview script shows "File not found" +**Problem:** Running `npm run contributors:preview username` shows file not found + +**Solutions:** +1. Make sure you're in the repository root directory +2. Check that your file is named correctly: `contributors/username.json` +3. Use lowercase for the filename + +### Contributions not showing in README after merge +**Problem:** Your PR was merged but you don't see your profile in the README + +**Explanation:** The GitHub Action needs a few minutes to run and update the README. Check back in 5-10 minutes. + +### Test script errors +**Problem:** The test script fails with various errors + +**Solutions:** +1. Make sure you have all-contributors-cli installed: `npm install` +2. Check that your JSON file is valid +3. Ensure you're running from the repository root directory + +**Note:** All scripts are now JavaScript-based, so you only need Node.js installed (no Python required) + +## Still Having Issues? + +If you're still experiencing problems: + +1. Check [GitHub Discussions](https://github.com/OpenSource-Communities/guestbook/discussions) +2. Search existing issues +3. Create a new issue with: + - The command you ran + - The full error message + - Your operating system + +## Alternative: Manual Validation + +If the scripts aren't working for you: + +1. Create your JSON file manually +2. Validate it at [jsonlint.com](https://jsonlint.com/) +3. Ensure: + - Filename matches your GitHub username + - All required fields are present + - Valid contribution types are used +4. Submit your PR + +The GitHub Actions will validate your contribution when you submit the PR! \ No newline at end of file diff --git a/docs/guides/migration-to-js.md b/docs/guides/migration-to-js.md new file mode 100644 index 0000000..bdc5413 --- /dev/null +++ b/docs/guides/migration-to-js.md @@ -0,0 +1,41 @@ +# Migration from Python to JavaScript Scripts + +All contributor scripts have been migrated from Python to JavaScript for better consistency and ease of use. + +## What Changed? + +### Before (Python-based) +- Required Python 3 installation +- Scripts used `.py` extensions +- Mixed technology stack (Node.js + Python) + +### After (JavaScript-based) +- Only requires Node.js (which you already have for npm) +- Scripts use `.js` extensions +- Consistent JavaScript/Node.js stack + +## Updated Commands + +The npm scripts remain the same: +- `npm run contributors:preview username` - Preview your contribution +- `npm run contributors:validate` - Validate all contributor files +- `npm run contributors:test username` - Full test with README generation + +## Benefits + +1. **Single dependency**: Only Node.js needed (no Python installation required) +2. **Better Windows support**: Node.js works consistently across all platforms +3. **Faster execution**: No need to spawn Python processes +4. **Easier maintenance**: All scripts in the same language + +## For Script Developers + +If you need to modify the scripts: +- All scripts are in `scripts/` directory +- Use Node.js built-in modules (fs, path, child_process) +- Follow the existing patterns for consistency +- Make scripts executable: `chmod +x scripts/*.js` + +## Backward Compatibility + +The old Python scripts are still in the repository but are no longer used by the npm commands. They may be removed in a future cleanup. \ No newline at end of file diff --git a/scripts/preview-contribution.js b/scripts/preview-contribution.js new file mode 100755 index 0000000..f2fa51e --- /dev/null +++ b/scripts/preview-contribution.js @@ -0,0 +1,147 @@ +#!/usr/bin/env node + +/** + * Simple preview script for contributor JSON files + * Shows how the contributor will appear without modifying any files + */ + +const fs = require('fs'); +const path = require('path'); + +function previewContributor(username) { + const contributorFile = path.join('contributors', `${username}.json`); + + if (!fs.existsSync(contributorFile)) { + console.log(`โŒ File not found: ${contributorFile}`); + console.log(`๐Ÿ’ก Create ${contributorFile} first!`); + return false; + } + + let data; + try { + const content = fs.readFileSync(contributorFile, 'utf8'); + data = JSON.parse(content); + } catch (e) { + if (e instanceof SyntaxError) { + console.log(`โŒ Invalid JSON in ${contributorFile}: ${e.message}`); + } else { + console.log(`โŒ Error reading ${contributorFile}: ${e.message}`); + } + return false; + } + + // Validate required fields + const required = ['name', 'github', 'contributions']; + const missing = required.filter(field => !data[field] || (Array.isArray(data[field]) && data[field].length === 0)); + + if (missing.length > 0) { + console.log(`โŒ Missing required fields: ${missing.join(', ')}`); + return false; + } + + // Check username match + if (data.github !== username) { + console.log(`โŒ Username mismatch:`); + console.log(` Filename: ${username}.json`); + console.log(` JSON github field: ${data.github}`); + console.log(` These must match!`); + return false; + } + + console.log('โœ… Contributor file validation passed!'); + console.log(); + + // Show preview + const name = data.name; + const github = data.github; + const profile = data.profile || `https://github.com/${github}`; + const contributions = data.contributions; + + console.log('๐ŸŽจ Preview of your contributor profile:'); + console.log('='.repeat(50)); + console.log(`๐Ÿ‘ค Name: ${name}`); + console.log(`๐Ÿ”— Profile: ${profile}`); + console.log(`๐Ÿ“ท Avatar: https://github.com/${github}.png`); + console.log(`๐ŸŽฏ Contributions: ${contributions.join(', ')}`); + console.log(); + + // Show contribution icons + const contributionIcons = { + 'a11y': 'โ™ฟ๏ธ', 'audio': '๐Ÿ”Š', 'blog': '๐Ÿ“', 'bug': '๐Ÿ›', + 'business': '๐Ÿ’ผ', 'code': '๐Ÿ’ป', 'content': '๐Ÿ–‹', 'data': '๐Ÿ”ฃ', + 'design': '๐ŸŽจ', 'doc': '๐Ÿ“–', 'eventOrganizing': '๐Ÿ“‹', 'example': '๐Ÿ’ก', + 'financial': '๐Ÿ’ต', 'fundingFinding': '๐Ÿ”', 'ideas': '๐Ÿค”', 'infra': '๐Ÿš‡', + 'maintenance': '๐Ÿšง', 'mentoring': '๐Ÿง‘โ€๐Ÿซ', 'platform': '๐Ÿ“ฆ', 'plugin': '๐Ÿ”Œ', + 'projectManagement': '๐Ÿ“†', 'promotion': '๐Ÿ“ฃ', 'question': '๐Ÿ’ฌ', 'research': '๐Ÿ”ฌ', + 'review': '๐Ÿ‘€', 'security': '๐Ÿ›ก๏ธ', 'talk': '๐Ÿ“ข', 'test': 'โš ๏ธ', + 'tool': '๐Ÿ”ง', 'translation': '๐ŸŒ', 'tutorial': 'โœ…', 'userTesting': '๐Ÿ““', + 'video': '๐Ÿ“น' + }; + + console.log('๐Ÿท๏ธ Your contribution icons:'); + contributions.forEach(contrib => { + const icon = contributionIcons[contrib] || 'โ“'; + console.log(` ${icon} ${contrib}`); + }); + + console.log(); + console.log('๐Ÿ“ฑ How it will look in the README:'); + console.log('='.repeat(50)); + + // Generate HTML preview (simplified) + const iconsHtml = contributions + .map(contrib => `${contributionIcons[contrib] || 'โ“'}`) + .join(' '); + + const htmlPreview = ` + + + ${name} +
+ ${name} +
+
+ ${iconsHtml} +`; + + console.log(htmlPreview); + console.log(); + console.log('='.repeat(50)); + console.log('โœ… Your contribution looks great!'); + console.log(); + console.log('๐Ÿš€ Next steps:'); + console.log(` 1. git add ${contributorFile}`); + console.log(` 2. git commit -m 'Add ${name} as a contributor'`); + console.log(` 3. git push origin your-branch-name`); + console.log(` 4. Create your pull request on GitHub!`); + console.log(); + console.log('๐Ÿ’ก After your PR is merged, this exact profile will appear in the README automatically!'); + + return true; +} + +function main() { + const args = process.argv.slice(2); + + if (args.length !== 1) { + console.log('Usage: node scripts/preview-contribution.js your-username'); + console.log('Example: node scripts/preview-contribution.js johndoe'); + process.exit(1); + } + + const username = args[0]; + const success = previewContributor(username); + + if (!success) { + console.log(); + console.log('๐Ÿ”ง Need help?'); + console.log(' - Check the template in docs/guides/contributor-guide.md'); + console.log(' - Validate JSON syntax at https://jsonlint.com/'); + console.log(' - Ask questions in GitHub Discussions'); + process.exit(1); + } +} + +if (require.main === module) { + main(); +} \ No newline at end of file diff --git a/scripts/test-locally.js b/scripts/test-locally.js new file mode 100755 index 0000000..b36dda2 --- /dev/null +++ b/scripts/test-locally.js @@ -0,0 +1,192 @@ +#!/usr/bin/env node + +/** + * Local testing script for contributors + * This allows contributors to test their JSON file and see how it will appear in the README + */ + +const fs = require('fs'); +const path = require('path'); +const { execSync } = require('child_process'); + +function testContributor(username) { + console.log('๐Ÿงช Testing your contributor file locally...'); + + const contributorFile = path.join('contributors', `${username}.json`); + + // Check if the contributor file exists + if (!fs.existsSync(contributorFile)) { + console.error(`โŒ File not found: ${contributorFile}`); + console.error('๐Ÿ’ก Make sure you\'ve created your contributor file first!'); + process.exit(1); + } + + console.log(`๐Ÿ“ Found contributor file: ${contributorFile}`); + + // Validate the JSON file + console.log('๐Ÿ” Validating JSON format...'); + let data; + try { + const content = fs.readFileSync(contributorFile, 'utf8'); + data = JSON.parse(content); + console.log('โœ… JSON format is valid'); + } catch (e) { + console.error(`โŒ Invalid JSON format in ${contributorFile}`); + console.error('๐Ÿ’ก Check your JSON syntax - use quotes around all strings!'); + process.exit(1); + } + + // Validate required fields + console.log('๐Ÿ” Checking required fields...'); + const errors = []; + const requiredFields = ['name', 'github', 'contributions']; + + requiredFields.forEach(field => { + if (!data[field]) { + errors.push(`Missing field: ${field}`); + } else if (field === 'contributions' && (!Array.isArray(data[field]) || data[field].length === 0)) { + errors.push('contributions must be a non-empty array'); + } + }); + + if (data.github !== username) { + errors.push(`GitHub username '${data.github}' doesn't match filename '${username}.json'`); + } + + if (errors.length > 0) { + console.error('โŒ Validation errors:'); + errors.forEach(error => console.error(` - ${error}`)); + process.exit(1); + } + + console.log('โœ… All required fields present and valid'); + console.log(`๐Ÿ“ Name: ${data.name}`); + console.log(`๐Ÿ‘ค GitHub: @${data.github}`); + if (data.profile) { + console.log(`๐Ÿ”— Profile: ${data.profile}`); + } + console.log(`๐ŸŽฏ Contributions: ${data.contributions.join(', ')}`); + + // Create backups + console.log('๐Ÿ’พ Creating backup of current README...'); + if (fs.existsSync('README.md')) { + fs.copyFileSync('README.md', 'README.md.backup'); + } + if (fs.existsSync('.all-contributorsrc')) { + fs.copyFileSync('.all-contributorsrc', '.all-contributorsrc.backup'); + } + + // Create test all-contributors config + console.log('โš™๏ธ Setting up test environment...'); + const testConfig = { + projectName: "guestbook", + projectOwner: "OpenSource-Community", + repoType: "github", + repoHost: "https://github.com", + files: ["README.md"], + imageSize: 100, + commit: false, + commitConvention: "angular", + contributors: [ + { + login: data.github, + name: data.name, + avatar_url: `https://github.com/${data.github}.png`, + profile: data.profile || `https://github.com/${data.github}`, + contributions: data.contributions + } + ] + }; + + fs.writeFileSync('.all-contributorsrc', JSON.stringify(testConfig, null, 2)); + console.log('โœ… Test configuration created'); + + // Generate test README section + console.log('๐ŸŽจ Generating test preview...'); + try { + execSync('npx all-contributors generate', { stdio: 'inherit' }); + } catch (e) { + console.error('โŒ Error generating preview'); + // Restore files + restoreFiles(); + process.exit(1); + } + + // Show the contributor section + console.log('\n๐ŸŽ‰ SUCCESS! Here\'s how your contribution will appear:'); + console.log('==================================================\n'); + + // Extract and show the contributor section + try { + const readmeContent = fs.readFileSync('README.md', 'utf8'); + const startMarker = ''; + + const startIndex = readmeContent.indexOf(startMarker); + const endIndex = readmeContent.indexOf(endMarker); + + if (startIndex !== -1 && endIndex !== -1) { + const contributorsSection = readmeContent.substring(startIndex, endIndex + endMarker.length); + console.log(contributorsSection); + } else { + console.log('Could not extract contributors section'); + } + } catch (e) { + console.error('Error reading README:', e.message); + } + + console.log('\n==================================================\n'); + + // Restore original files + restoreFiles(); + + console.log('โœ… Test complete! Your contributor file looks good.\n'); + console.log('๐Ÿš€ Next steps:'); + console.log(` 1. git add ${contributorFile}`); + console.log(` 2. git commit -m 'Add ${username} as a contributor'`); + console.log(` 3. git push origin your-branch-name`); + console.log(' 4. Create your pull request on GitHub!'); + console.log('\n๐Ÿ’ก Remember: The actual README will be updated automatically after your PR is merged!'); +} + +function restoreFiles() { + console.log('๐Ÿ”„ Restoring original files...'); + + if (fs.existsSync('README.md.backup')) { + fs.renameSync('README.md.backup', 'README.md'); + } + if (fs.existsSync('.all-contributorsrc.backup')) { + fs.renameSync('.all-contributorsrc.backup', '.all-contributorsrc'); + } +} + +function main() { + const args = process.argv.slice(2); + + if (args.length !== 1) { + console.log('Usage: node scripts/test-locally.js your-username'); + console.log('Example: node scripts/test-locally.js johndoe'); + process.exit(1); + } + + const username = args[0]; + + try { + testContributor(username); + } catch (e) { + console.error('Error:', e.message); + restoreFiles(); + process.exit(1); + } +} + +// Handle interruptions +process.on('SIGINT', () => { + console.log('\n\nInterrupted! Restoring files...'); + restoreFiles(); + process.exit(1); +}); + +if (require.main === module) { + main(); +} \ No newline at end of file diff --git a/scripts/validate-contributor.js b/scripts/validate-contributor.js new file mode 100755 index 0000000..55df1a6 --- /dev/null +++ b/scripts/validate-contributor.js @@ -0,0 +1,162 @@ +#!/usr/bin/env node + +/** + * Validates all contributor JSON files + */ + +const fs = require('fs'); +const path = require('path'); + +function validateContributorFile(filepath) { + const filename = path.basename(filepath); + const username = filename.replace('.json', ''); + + // Skip template files + if (filename === 'example-contributor.json' || filename === '.gitkeep' || filename === 'README.md') { + return { valid: true, skipped: true }; + } + + let data; + try { + const content = fs.readFileSync(filepath, 'utf8'); + data = JSON.parse(content); + } catch (e) { + return { + valid: false, + errors: [`Invalid JSON: ${e.message}`] + }; + } + + const errors = []; + const warnings = []; + + // Check required fields + const required = ['name', 'github', 'contributions']; + required.forEach(field => { + if (!data[field]) { + errors.push(`Missing required field: ${field}`); + } + }); + + // Check github username matches filename + if (data.github && data.github !== username) { + errors.push(`GitHub username '${data.github}' doesn't match filename '${filename}'`); + } + + // Check contributions is an array + if (data.contributions && !Array.isArray(data.contributions)) { + errors.push('contributions must be an array'); + } else if (data.contributions && data.contributions.length === 0) { + errors.push('contributions array cannot be empty'); + } + + // Validate contribution types + const validContributions = [ + 'a11y', 'audio', 'blog', 'bug', 'business', 'code', 'content', 'data', + 'design', 'doc', 'eventOrganizing', 'example', 'financial', 'fundingFinding', + 'ideas', 'infra', 'maintenance', 'mentoring', 'platform', 'plugin', + 'projectManagement', 'promotion', 'question', 'research', 'review', + 'security', 'talk', 'test', 'tool', 'translation', 'tutorial', + 'userTesting', 'video' + ]; + + if (data.contributions && Array.isArray(data.contributions)) { + data.contributions.forEach(contrib => { + if (!validContributions.includes(contrib)) { + warnings.push(`Unknown contribution type: ${contrib}`); + } + }); + } + + // Check profile URL format + if (data.profile && !data.profile.startsWith('http')) { + warnings.push('profile should be a full URL starting with http:// or https://'); + } + + return { + valid: errors.length === 0, + errors, + warnings, + data + }; +} + +function main() { + console.log('๐Ÿ” Validating contributor files...\n'); + + const contributorsDir = path.join(process.cwd(), 'contributors'); + + if (!fs.existsSync(contributorsDir)) { + console.log('โŒ Contributors directory not found!'); + process.exit(1); + } + + const files = fs.readdirSync(contributorsDir).filter(f => f.endsWith('.json')); + + if (files.length === 0) { + console.log('โŒ No contributor JSON files found!'); + process.exit(1); + } + + let totalFiles = 0; + let validFiles = 0; + let skippedFiles = 0; + let errorFiles = 0; + let totalWarnings = 0; + + files.forEach(file => { + const filepath = path.join(contributorsDir, file); + const result = validateContributorFile(filepath); + + if (result.skipped) { + skippedFiles++; + return; + } + + totalFiles++; + + if (result.valid && result.warnings.length === 0) { + console.log(`โœ… ${file}`); + validFiles++; + } else if (result.valid && result.warnings.length > 0) { + console.log(`โš ๏ธ ${file}`); + result.warnings.forEach(warning => { + console.log(` โš ๏ธ ${warning}`); + }); + validFiles++; + totalWarnings += result.warnings.length; + } else { + console.log(`โŒ ${file}`); + result.errors.forEach(error => { + console.log(` โŒ ${error}`); + }); + if (result.warnings) { + result.warnings.forEach(warning => { + console.log(` โš ๏ธ ${warning}`); + }); + totalWarnings += result.warnings.length; + } + errorFiles++; + } + }); + + console.log('\n๐Ÿ“Š Validation Summary:'); + console.log(` Files checked: ${totalFiles}`); + console.log(` Valid: ${validFiles}`); + console.log(` Errors: ${errorFiles}`); + console.log(` Warnings: ${totalWarnings}`); + if (skippedFiles > 0) { + console.log(` Skipped: ${skippedFiles} (template files)`); + } + + if (errorFiles > 0) { + console.log('\nโŒ Validation failed! Fix the errors above.'); + process.exit(1); + } else { + console.log('\nโœ… All contributor files are valid!'); + } +} + +if (require.main === module) { + main(); +} \ No newline at end of file From 2b2632cb4518a2b28bbc7f1f787bc328af5fc2fd Mon Sep 17 00:00:00 2001 From: BekahHW Date: Tue, 16 Sep 2025 10:36:12 -0400 Subject: [PATCH 6/6] Fix merge errors --- .github/workflows/validate-pr.yml | 128 +++++++++++++++--------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/.github/workflows/validate-pr.yml b/.github/workflows/validate-pr.yml index 4aabf31..92af544 100644 --- a/.github/workflows/validate-pr.yml +++ b/.github/workflows/validate-pr.yml @@ -52,70 +52,70 @@ jobs: filename=$(basename "$file" .json) # Validate JSON structure - python3 -c " -import json -import sys + python3 -c ' + import json + import sys -try: - with open('$file', 'r') as f: - data = json.load(f) - - required_fields = ['name', 'github', 'contributions', 'profile'] - missing_fields = [field for field in required_fields if field not in data or not data[field]] - - if missing_fields: - print(f'โŒ ERROR: Missing required fields: {missing_fields}') - sys.exit(1) - - # Check if filename matches github username - if data['github'] != '$filename': - print(f'โŒ ERROR: Filename must match GitHub username') - print(f' File: $filename.json') - print(f' GitHub username in file: {data[\"github\"]}') - print(f' Should be: {data[\"github\"]}.json') - sys.exit(1) - - print('โœ… Contributor file is valid!') - -except json.JSONDecodeError as e: - print(f'โŒ ERROR: Invalid JSON format: {e}') - sys.exit(1) -except Exception as e: - print(f'โŒ ERROR: {e}') - sys.exit(1) -" || exit 1 - done - - echo "โœ… All validations passed!" - - - name: Welcome comment for new contributors - if: steps.changed-files.outputs.any_changed == 'true' - uses: actions/github-script@v7 - with: - script: | - const changedFiles = '${{ steps.changed-files.outputs.all_changed_files }}'; - - if (changedFiles.trim()) { - const comment = `๐ŸŽ‰ **Welcome to the guestbook!** - - Thank you for contributing! Your submission looks good and follows the new conflict-free process. + try: + with open("'"$file"'", "r") as f: + data = json.load(f) - Once this PR is merged: - - โœ… You'll be automatically added to the contributors list in the README - - ๐ŸŽ“ You can continue with the next step in the [Intro to Open Source course](https://opensauced.pizza/learn/intro-to-oss/) - - ๐ŸŒŸ Consider creating a [highlight](https://app.opensauced.pizza/feed) of your contribution! + required_fields = ["name", "github", "contributions"] + missing_fields = [field for field in required_fields if field not in data or not data[field]] - **What happens next?** - - A maintainer will review your PR - - After merge, a GitHub Action will automatically update the README - - You'll see your profile appear in the contributors section! - - Thanks for being part of the open source community! ๐Ÿš€`; - - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: comment - }); - } \ No newline at end of file + if missing_fields: + print(f"โŒ ERROR: Missing required fields: {missing_fields}") + sys.exit(1) + + # Check if filename matches github username + if data["github"] != "'"$filename"'": + print(f"โŒ ERROR: Filename must match GitHub username") + print(f" File: {filename}.json") + print(f" GitHub username in file: {data['github']}") + print(f" Should be: {data['github']}.json") + sys.exit(1) + + print("โœ… Contributor file is valid!") + + except json.JSONDecodeError as e: + print(f"โŒ ERROR: Invalid JSON format: {e}") + sys.exit(1) + except Exception as e: + print(f"โŒ ERROR: {e}") + sys.exit(1) + ' || exit 1 + done + + echo "โœ… All validations passed!" + + - name: Welcome comment for new contributors + if: steps.changed-files.outputs.any_changed == 'true' + uses: actions/github-script@v7 + with: + script: | + const changedFiles = '${{ steps.changed-files.outputs.all_changed_files }}'; + + if (changedFiles.trim()) { + const comment = `๐ŸŽ‰ **Welcome to the guestbook!** + + Thank you for contributing! Your submission looks good and follows the new conflict-free process. + + Once this PR is merged: + - โœ… You'll be automatically added to the contributors list in the README + - ๐ŸŽ“ You can continue with the next step in the [Intro to Open Source course](https://opensauced.pizza/learn/intro-to-oss/) + - ๐ŸŒŸ Consider creating a [highlight](https://app.opensauced.pizza/feed) of your contribution! + + **What happens next?** + - A maintainer will review your PR + - After merge, a GitHub Action will automatically update the README + - You'll see your profile appear in the contributors section! + + Thanks for being part of the open source community! ๐Ÿš€`; + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: comment + }); + } \ No newline at end of file