بوابات المطورين مع Backstage

قوالب البرمجيات (المُنشئ)

4 دقيقة للقراءة

قوالب البرمجيات هي الميزة القاتلة لـ Backstage لفرق المنصات. تمكّن المطورين من إنشاء مشاريع جديدة تتبع تلقائياً أفضل ممارسات مؤسستك—هذا حيث تصبح المسارات الذهبية حقيقة.

لماذا قوالب البرمجيات؟

بدون القوالب، كل مشروع جديد يبدأ بشكل مختلف:

بدون القوالب:
المطور أ: "سأعد CI/CD يدوياً..."
المطور ب: "دعني أنسخ من مشروع قديم..."
المطور ج: "ما هي الطريقة القياسية مرة أخرى؟"

النتيجة: مشاريع غير متسقة، ثغرات أمنية، توثيق مفقود

مع القوالب:
جميع المطورين: "انقر → املأ النموذج → احصل على مشروع موحد"

النتيجة: هيكل متسق، أمان مدمج، توثيق متضمن

تشريح القالب

قالب Backstage له ثلاثة أقسام رئيسية:

# هيكل template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: template-name
  title: عنوان قابل للقراءة
  description: ما ينشئه هذا القالب
  tags: [tag1, tag2]
spec:
  owner: platform-team
  type: service  # service, website, library, إلخ

  # القسم 1: المعاملات (إدخال المستخدم)
  parameters:
    - title: عنوان الخطوة 1
      properties:
        fieldName:
          type: string

  # القسم 2: الخطوات (الإجراءات للتنفيذ)
  steps:
    - id: step-id
      name: اسم الخطوة
      action: action:name
      input:
        key: value

  # القسم 3: المخرجات (ما يظهر للمستخدم)
  output:
    links:
      - title: عنوان الرابط
        url: ${{ steps.step-id.output.someUrl }}

مثال قالب كامل

إليك قالب Node.js API جاهز للإنتاج:

apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: nodejs-api-template
  title: Node.js REST API
  description: |
    ينشئ Node.js REST API جاهز للإنتاج مع Express،
    TypeScript، Docker، بيانات Kubernetes، و CI/CD.
  tags:
    - nodejs
    - typescript
    - api
    - recommended
spec:
  owner: group:platform-team
  type: service

  parameters:
    # الخطوة 1: المعلومات الأساسية
    - title: معلومات الخدمة
      required:
        - name
        - description
        - owner
      properties:
        name:
          title: اسم الخدمة
          type: string
          description: اسم فريد لخدمتك
          pattern: '^[a-z0-9-]+$'
          ui:autofocus: true
          ui:help: 'أحرف صغيرة وأرقام وشرطات فقط'
        description:
          title: الوصف
          type: string
          description: ماذا تفعل هذه الخدمة؟
        owner:
          title: المالك
          type: string
          description: الفريق الذي يملك هذه الخدمة
          ui:field: OwnerPicker
          ui:options:
            catalogFilter:
              kind: Group

    # الخطوة 2: الخيارات التقنية
    - title: التكوين التقني
      properties:
        database:
          title: تضمين قاعدة البيانات؟
          type: boolean
          default: false
        databaseType:
          title: نوع قاعدة البيانات
          type: string
          enum:
            - postgresql
            - mysql
            - mongodb
          enumNames:
            - PostgreSQL (موصى به)
            - MySQL
            - MongoDB
          default: postgresql
          ui:widget: select
          ui:options:
            hidden: '{{ not parameters.database }}'
        authentication:
          title: طريقة المصادقة
          type: string
          enum:
            - jwt
            - oauth2
            - none
          default: jwt

    # الخطوة 3: إعدادات المستودع
    - title: تكوين المستودع
      required:
        - repoUrl
      properties:
        repoUrl:
          title: موقع المستودع
          type: string
          ui:field: RepoUrlPicker
          ui:options:
            allowedHosts:
              - github.com
            allowedOwners:
              - acme-corp

  steps:
    # الخطوة 1: جلب وتشكيل الهيكل
    - id: fetch-base
      name: جلب القالب الأساسي
      action: fetch:template
      input:
        url: ./skeleton
        values:
          name: ${{ parameters.name }}
          description: ${{ parameters.description }}
          owner: ${{ parameters.owner }}
          database: ${{ parameters.database }}
          databaseType: ${{ parameters.databaseType }}
          authentication: ${{ parameters.authentication }}

    # الخطوة 2: إضافة تكوين قاعدة البيانات إذا لزم الأمر
    - id: fetch-database
      name: إضافة تكوين قاعدة البيانات
      if: ${{ parameters.database }}
      action: fetch:template
      input:
        url: ./skeleton-database-${{ parameters.databaseType }}
        targetPath: ./src/database

    # الخطوة 3: إنشاء مستودع GitHub
    - id: publish
      name: النشر إلى GitHub
      action: publish:github
      input:
        repoUrl: ${{ parameters.repoUrl }}
        description: ${{ parameters.description }}
        defaultBranch: main
        protectDefaultBranch: true
        requireCodeOwnerReviews: true
        repoVisibility: internal

    # الخطوة 4: إنشاء بيئات GitHub
    - id: github-environments
      name: إنشاء البيئات
      action: github:environment:create
      input:
        repoUrl: ${{ parameters.repoUrl }}
        name: production
        deploymentBranchPolicy:
          protectedBranches: true

    # الخطوة 5: التسجيل في كتالوج Backstage
    - id: register
      name: التسجيل في الكتالوج
      action: catalog:register
      input:
        repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
        catalogInfoPath: /catalog-info.yaml

    # الخطوة 6: تشغيل CI الأولي
    - id: trigger-ci
      name: تشغيل خط أنابيب CI
      action: github:actions:dispatch
      input:
        repoUrl: ${{ parameters.repoUrl }}
        workflowId: ci.yaml
        branchOrTagName: main

  output:
    links:
      - title: المستودع
        url: ${{ steps.publish.output.remoteUrl }}
      - title: فتح في الكتالوج
        icon: catalog
        entityRef: ${{ steps.register.output.entityRef }}
      - title: خط أنابيب CI
        url: ${{ steps.publish.output.remoteUrl }}/actions

هيكل الهيكل العظمي للقالب

مجلد ./skeleton يحتوي على ملفات القالب:

skeleton/
├── catalog-info.yaml
├── package.json
├── tsconfig.json
├── Dockerfile
├── .github/
│   └── workflows/
│       ├── ci.yaml
│       └── deploy.yaml
├── kubernetes/
│   ├── deployment.yaml
│   └── service.yaml
├── src/
│   ├── index.ts
│   ├── routes/
│   └── middleware/
└── docs/
    └── index.md

مثال ملف هيكل مع القوالب:

# skeleton/catalog-info.yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: ${{ values.name }}
  description: ${{ values.description }}
  annotations:
    github.com/project-slug: acme-corp/${{ values.name }}
    backstage.io/techdocs-ref: dir:.
spec:
  type: service
  lifecycle: experimental
  owner: ${{ values.owner }}

الإجراءات المدمجة

يوفر Backstage العديد من الإجراءات المدمجة:

# إجراءات المُنشئ الشائعة
actions:

  fetch:
    - fetch:template      # جلب وعرض القالب
    - fetch:plain         # جلب بدون عرض

  publish:
    - publish:github      # إنشاء مستودع GitHub
    - publish:gitlab      # إنشاء مستودع GitLab
    - publish:bitbucket   # إنشاء مستودع Bitbucket

  catalog:
    - catalog:register    # تسجيل الكيان في الكتالوج
    - catalog:write       # كتابة catalog-info.yaml

  github:
    - github:actions:dispatch  # تشغيل سير العمل
    - github:environment:create # إنشاء البيئة
    - github:issues:create     # إنشاء مشكلة

  debug:
    - debug:log           # تسجيل القيم للتصحيح

الإجراءات المخصصة

أنشئ إجراءات مخصصة لمؤسستك:

// plugins/scaffolder-backend-module-acme/src/actions/createDatabase.ts
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';

export const createDatabaseAction = createTemplateAction({
  id: 'acme:database:create',
  description: 'ينشئ قاعدة بيانات عبر Crossplane',
  schema: {
    input: {
      type: 'object',
      required: ['name', 'engine'],
      properties: {
        name: { type: 'string' },
        engine: { type: 'string', enum: ['postgresql', 'mysql'] },
        size: { type: 'string', default: 'small' },
      },
    },
  },
  async handler(ctx) {
    const { name, engine, size } = ctx.input;

    // إنشاء مطالبة Crossplane
    await ctx.createKubernetesResource({
      apiVersion: 'database.acme.io/v1',
      kind: 'DatabaseClaim',
      metadata: { name },
      spec: { engine, size },
    });

    ctx.output('databaseName', name);
    ctx.output('connectionSecretName', `${name}-connection`);
  },
});

في الدرس التالي، سنستكشف TechDocs ونظام الإضافات البيئي. :::