diff --git a/blog/2024-08-26-ospp-2023-analysis/index.mdx b/blog/2024-08-26-ospp-2023-analysis/index.mdx new file mode 100644 index 0000000..4b4dcc8 --- /dev/null +++ b/blog/2024-08-26-ospp-2023-analysis/index.mdx @@ -0,0 +1,126 @@ +--- +slug: ospp-2023-analysis +title: OSPP 2023 深度洞察报告 +authors: [zsy, ww] +--- + +import SimpleECharts from '@site/src/components/SimpleECharts'; +import SimpleTable from '@site/src/components/SimpleTable'; + +## 背景介绍 + +[开源之夏 OSPP](https://summer-ospp.ac.cn/) 是中国科学院软件研究所发起的“开源软件供应链点亮计划”系列暑期活动,旨在鼓励高校学生积极参与开源软件的开发维护,促进优秀开源软件社区的蓬勃发展,至今已成功举办五届(2020 ~ 2024),X-lab 开放实验室从第一届就开始深度参与。 + +OpenDigger 作为一直以来深入参与 OSPP 的开源数据研究项目,也在此就 OSPP 2023 年的数据做一次深度的分析,也算是对 OSPP 社区的一次回馈。 + +## OSPP 2023 宏观数据 + +根据 OSPP 社区的数据报告,2023 年度,OSPP 总共发布了项目 **593** 个,有学生中选项目共计 **495** 个,最终结项项目为 **421** 个,结项率高达 **71%**。 + +最终结项项目大部分除了个别与操作系统内核相关的社区使用了自己的 git 仓库外,大部分社区均托管于 GitHub(298 个)、Gitee(112 个)等代码托管平台上,平台的总体分布如下: + + + +从结项项目的学生所属高校来看,结项的 **421** 个项目由分别来自 **144** 所高校的学生最终完成,其中北京邮电大学、浙江大学、华中科技大学以 **20** 个以上的学生数量领跑各高校,具体的分布如下所示: + + + +## 年度贡献度分析 + +除了上述一些统计数据外,我们也希望可以给出一些更加深入的洞察,例如每个高校中不同学生在社区中具体的贡献度等,这种精细化的分析也有助于我们进一步观察学生在整个过程中对于项目的协同参与程度,而不仅仅局限于学生是否仅是完成了一个特定的任务。 + +> 注意:受限于 OpenDigger 目前的底层基础数据,下述分析将仅包含 GitHub、Gitee 平台上的数据。 + +我们使用了 2023 全年的贡献度数据和社区 OpenRank 算法对参与到各社区学生的参与度进行了详细的分析,最终统计到各高校总体贡献度前 20 名如下表所示: + + + +
+ +我们在给出了高校总体贡献度的同时也给出了校人均 OpenRank 贡献度,可以看到北京邮电大学、华中科技大学、浙江大学依凭学生数量优势依然排在贡献榜前三位,但也有些高校因为很高的人均 OpenRank 贡献度而上榜,如复旦大学、重庆邮电大学、陇东学院、武汉大学、成都信息工程大学等,他们在学生数量上并不占优,但因为个别学生的贡献度较高而使得最终的排名较高。 + +为了进一步观察学生的贡献情况,我们也对学生贡献者进行了 OpenRank 贡献度的排名,OpenRank 前 20 的学生如下: + + + +
+ +通过对于学生个体的分析,一些贡献度极高的学生就可以清晰的看到,例如来自陇东学院的姬同学在 Spring Cloud Alibaba 社区、来自重庆邮电大学的孟同学在 Apache Skywalking 社区、来自成都信息工程大学的黄同学在 CubeFS 社区、来自武汉大学的乔同学在 Apache RocketMQ 社区的参与,他们都仅凭一己之力将自己学校的总体贡献度拉入到高校前 20。 + +同时上表也给出了这些同学从 2023 年 1 月到 2024 年 7 月中在参与项目中的活跃月数,可以看到前 20 位的同学的活跃月数均达到了 6 个月以上,而上述提到的几位同学贡献时长都达到了 12 个月以上,这里也体现出了 OpenRank 鼓励长期贡献的价值取向。 + +## 后续持续贡献分析 + +我们可以看到,OSPP 拉动了大量高校的优秀学生在校期间就深入参与到开源社区的贡献之中,那么这些学生后续的活跃情况如何呢?为此我们也进行了更长期的跟踪分析,看一下在 OSPP 结束之后,还有多少的同学继续留在社区中持续的参与贡献。 + + + +上面的折线图是 2023 年 1 月到 2024 年 7 月各高校的贡献度堆叠图,我们可以看到 2023 年 3 月开学季同学们均没有参与到社区中,除此之外,2023 年 4 月以来同学们开始逐渐参与贡献,到 9 月份达到一个顶峰,之后逐渐回落,到 2024 年 1 月后趋于平缓稳定。 + + + +
+ +从这些同学在 2024.7 月的贡献情况来看,当月还有 **32** 位同学在自己曾经贡献的社区中继续活跃,而陇东学院的姬同学依然在非常活跃的深度参与到社区的开发活动之中,甚至贡献度相较 2023 年更高,这虽然与他今年再次中选 OSPP 项目有关,但也可以看到他已经深度融入到了 Spring Cloud Alibaba 社区,成为了一名长期贡献者。 diff --git a/blog/authors.yml b/blog/authors.yml index f8238e1..3ef12d7 100644 --- a/blog/authors.yml +++ b/blog/authors.yml @@ -1,6 +1,6 @@ ww: name: 王伟 - title: 华东师范大学 研究员 / X-lab 创始人 + title: 华东师范大学 教授 / X-lab 创始人 url: https://github.com/will-ww image_url: https://github.com/will-ww.png diff --git a/src/components/Leaderboard/BaseBoard.tsx b/src/components/Leaderboard/BaseBoard.tsx index 0fc7ea1..73e43eb 100644 --- a/src/components/Leaderboard/BaseBoard.tsx +++ b/src/components/Leaderboard/BaseBoard.tsx @@ -20,7 +20,7 @@ export function BaseBoard({ table }): JSX.Element { {/*
*/} {table.getRowModel().rows.map(row => ( - + {row.getVisibleCells().map(cell => { return {flexRender(cell.column.columnDef.cell, cell.getContext())} diff --git a/src/components/Leaderboard/styles.module.css b/src/components/Leaderboard/styles.module.css index 23f3bab..1704a8e 100644 --- a/src/components/Leaderboard/styles.module.css +++ b/src/components/Leaderboard/styles.module.css @@ -83,6 +83,10 @@ border-top: 1px solid rgba(175, 206, 232, 0.2) } +table tr:nth-child(even) { + background-color: rgba(175, 206, 232, 0.1); +} + .thr { border-top: none; } diff --git a/src/components/SimpleTable/index.tsx b/src/components/SimpleTable/index.tsx new file mode 100644 index 0000000..75f8f3b --- /dev/null +++ b/src/components/SimpleTable/index.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { BoardContainer } from '../Leaderboard/BoardContainer'; +import { BaseBoard } from '../Leaderboard/BaseBoard'; +import { useReactTable, createColumnHelper, getCoreRowModel } from '@tanstack/react-table'; +import { COLUMN_TYPE_RULES } from '../Leaderboard'; + +const helper = createColumnHelper<{ __index__: number }>(); + +export default (props: { title: string; data: any[]; options: any[] }): JSX.Element => { + const tableColumns = [helper.accessor(row => row, { + id: `__index__`, + header: () => '#', + cell: info => {info.getValue().__index__}, + size: 30, + })]; + tableColumns.push(...props.options.map((option, index) => { + const { name, width, type, fields } = option; + const column = helper.accessor(row => row, { + id: `${index}-${name}`, + header: () => name, + cell: info => { + const columnTypeRule = COLUMN_TYPE_RULES.find(rule => rule.name === type); + const renderProps = fields.map(field => info.getValue()[field]); + return columnTypeRule.renderer(...renderProps); + }, + size: width, + }); + return column; + })); + + const table = useReactTable({ + columns: tableColumns, + data: props.data, + getCoreRowModel: getCoreRowModel() + }); + + return ( + + + + ); +}