Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions backend/core/plugin/plugin_meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ type PluginIcon interface {
SvgIcon() string
}

// PluginDeprecation is implemented by plugins that have been deprecated.
// The DeprecationMessage should describe why the plugin is deprecated and
// what users should migrate to. Returns an empty string for non-deprecated
// plugins.
type PluginDeprecation interface {
DeprecationMessage() string
}

// PluginSource abstracts data sources
type PluginSource interface {
Connection() dal.Tabler
Expand Down
1 change: 1 addition & 0 deletions backend/core/runner/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ func LoadGoPlugins(basicRes context.BasicRes) errors.Error {
func LoadRemotePlugins(basicRes context.BasicRes) errors.Error {
remotePluginDir := basicRes.GetConfig("REMOTE_PLUGIN_DIR")
if remotePluginDir != "" {
basicRes.GetLogger().Warn(nil, "DEPRECATION WARNING: The Python plugin framework (PyDevLake) is deprecated and will be removed in 3 months. See https://github.com/apache/devlake/issues/9092 for the deprecation plan and migration guide. Please migrate Python plugins (e.g. azuredevops) to the Go-based equivalents (e.g. azuredevops_go).")
basicRes.GetLogger().Info("Loading remote plugins")
remote.Init(basicRes)
walkErr := filepath.WalkDir(remotePluginDir, func(path string, d fs.DirEntry, err error) error {
Expand Down
22 changes: 22 additions & 0 deletions backend/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,28 @@ limitations under the License.
-->
# Pydevlake

> **⚠️ DEPRECATED — Scheduled for removal.**
> The Python plugin framework (PyDevLake) is deprecated and will be removed from
> Apache DevLake in 3 months per the deprecation plan in
> [#9092](https://github.com/apache/devlake/issues/9092).
>
> Reasons:
> - Only one plugin (`azuredevops`) ever shipped on this framework; the `dbt`
> plugin was already removed (#8970).
> - No feature/fix commits to Python plugins since Dec 2025; only dependency
> refreshes and runtime bumps land.
> - A fully-featured Go implementation, `azuredevops_go`, now supersedes the
> Python `azuredevops` plugin (including on-premises support, #9014).
>
> **What you should do:**
> - New plugins: write them in **Go**. See `backend/plugins/` for 40+ reference
> implementations.
> - Existing `azuredevops` (Python) users: migrate to `azuredevops_go` (a
> migration guide will be published during the deprecation window).
>
> No new Python plugins will be accepted. Only critical security fixes will land
> during the deprecation window.

Pydevlake is a framework for writing plugins for [DevLake](https://devlake.apache.org/) in Python. The framework source code
can be found in [here](./pydevlake).

Expand Down
15 changes: 14 additions & 1 deletion backend/python/plugins/azuredevops/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,17 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
# Azure Devops Python Plugin
# Azure Devops Python Plugin

> **⚠️ DEPRECATED — Scheduled for removal in 3 months.**
> This Python `azuredevops` plugin is deprecated in favor of the Go-based
> [`azuredevops_go`](../../plugins/azuredevops_go) plugin, which has broader
> feature coverage (including Azure DevOps Server / on-premises support, #9014).
>
> Please migrate existing connections and scopes to `azuredevops_go`. A migration
> guide will be published during the deprecation window — see
> [#9092](https://github.com/apache/devlake/issues/9092) for the full plan and
> timeline.
>
> No new features or fixes (other than critical security fixes) will be accepted
> on this plugin.
9 changes: 7 additions & 2 deletions backend/server/api/plugininfo/plugininifo.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ type PluginMetric struct {
}

type PluginMeta struct {
Plugin string `json:"plugin"`
Metric PluginMetric `json:"metric"`
Plugin string `json:"plugin"`
Metric PluginMetric `json:"metric"`
Deprecated bool `json:"deprecated"`
}

type PluginMetas []PluginMeta
Expand Down Expand Up @@ -207,6 +208,10 @@ func GetPluginMetas(c *gin.Context) {
Plugin: name,
}

if dp, ok := p.(plugin.PluginDeprecation); ok {
pluginMeta.Deprecated = dp.DeprecationMessage() != ""
}

// if this plugin has the plugin task info
if pt, ok := p.(plugin.PluginMetric); ok {
var err1 errors.Error
Expand Down
12 changes: 12 additions & 0 deletions backend/server/services/remote/plugin/plugin_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,4 +238,16 @@ func (p *remotePluginImpl) MigrationScripts() []plugin.MigrationScript {
return append(p.migrationScripts, migrationscripts.All(p.name)...)
}

// DeprecationMessage implements plugin.PluginDeprecation. All remote (Python)
// plugins are deprecated and scheduled for removal in 3 months per the
// deprecation plan in issue #9092.
func (p *remotePluginImpl) DeprecationMessage() string {
return fmt.Sprintf(
"This Python plugin (%s) is DEPRECATED and will be removed in 3 months. "+
"Please migrate to the Go-based equivalent. "+
"See https://github.com/apache/devlake/issues/9092 for the deprecation plan and migration guide.",
p.name,
)
}

var _ models.RemotePlugin = (*remotePluginImpl)(nil)
3 changes: 3 additions & 0 deletions config-ui/src/plugins/register/azure/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ export const AzureConfig: IPluginConfig = {
name: 'Azure DevOps',
icon: ({ color }) => <Icon fill={color} />,
sort: 2,
isDeprecated: true,
deprecationMessage:
'This Python-based Azure DevOps plugin is DEPRECATED and will be removed in 3 months. Please migrate to the Go-based "Azure DevOps Go" plugin. See https://github.com/apache/devlake/issues/9092 for the deprecation plan and migration guide.',
connection: {
docLink: DOC_URL.PLUGIN.AZUREDEVOPS.BASIS,
initialValues: {},
Expand Down
8 changes: 8 additions & 0 deletions config-ui/src/routes/connection/connections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,12 @@ export const Connections = () => {
return (
<li key={plugin} onClick={() => handleShowListDialog(plugin)}>
{pluginConfig.isBeta && <span className="beta">Beta</span>}
{pluginConfig.isDeprecated && <span className="deprecated">Deprecated</span>}
<span className="logo">{pluginConfig.icon({ color: colorPrimary })}</span>
<span className="name">{pluginConfig.name}</span>
{pluginConfig.isDeprecated && pluginConfig.deprecationMessage && (
<span className="deprecation-note">{pluginConfig.deprecationMessage}</span>
)}
<span className="count">
{connectionCount ? (
<Badge color={colorPrimary} text={`${connectionCount} connections`} />
Expand All @@ -116,8 +120,12 @@ export const Connections = () => {
return (
<li key={plugin} onClick={() => handleShowListDialog(plugin)}>
{pluginConfig.isBeta && <span className="beta">Beta</span>}
{pluginConfig.isDeprecated && <span className="deprecated">Deprecated</span>}
<span className="logo">{pluginConfig.icon({ color: colorPrimary })}</span>
<span className="name">{pluginConfig.name}</span>
{pluginConfig.isDeprecated && pluginConfig.deprecationMessage && (
<span className="deprecation-note">{pluginConfig.deprecationMessage}</span>
)}
<span className="count">
{connectionCount ? (
<Badge color={colorPrimary} text={`${connectionCount} connections`} />
Expand Down
20 changes: 20 additions & 0 deletions config-ui/src/routes/connection/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,26 @@ export const Wrapper = styled.div`
border-radius: 8px;
}

& > .deprecated {
position: absolute;
top: 0;
left: 0;
padding: 4px 8px;
font-size: 12px;
color: ${({ theme }) => theme.colors.textInverse};
background-color: ${({ theme }) => theme.colors.error};
border-radius: 8px;
}

& > .deprecation-note {
margin-top: 4px;
padding: 0 8px;
font-size: 11px;
line-height: 1.4;
color: ${({ theme }) => theme.colors.error};
text-align: center;
}

& > .logo {
width: 60px;
height: 60px;
Expand Down
2 changes: 2 additions & 0 deletions config-ui/src/types/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export interface IPluginConfig {
icon: ({ color }: { color: string }) => React.ReactNode;
sort: number;
isBeta?: boolean;
isDeprecated?: boolean;
deprecationMessage?: string;
connection: {
docLink: string;
initialValues?: Record<string, any>;
Expand Down
Loading