Cours Vibe coding avec l'IA · Module 13: Clone de Twitch

Pipeline CI/CD - GitHub Actions

1 min de lecture

Déploiement automatisé.

Workflow GitHub Actions

1name: Deploy
2on:
3  push:
4    branches: [main]
5
6jobs:
7  deploy:
8    runs-on: ubuntu-latest
9    steps:
10      - uses: actions/checkout@v3
11      - uses: actions/setup-node@v3
12        with:
13          node-version: '20'
14      - run: npm ci
15      - run: npm test
16      - run: npm run build
17      - uses: amondnet/vercel-action@v25
18        with:
19          vercel-token: ${{ secrets.VERCEL_TOKEN }}

À bientôt !

Code de cette leçon : App.tsx
1'use client';
2
3import { useState } from 'react';
4
5interface Category {
6  id: string;
7  name: string;
8  boxArtUrl: string;
9  viewerCount: number;
10  tags: string[];
11}
12
13const mockCategories: Category[] = [
14  {
15    id: '1',
16    name: 'Software & Game Development',
17    boxArtUrl: 'https://images.unsplash.com/photo-1517694712202-14dd9538aa97?w=300&h=400&fit=crop',
18    viewerCount: 12547,
19    tags: ['Programming', 'Tutorial']
20  },
21  {
22    id: '2',
23    name: 'Science & Technology',
24    boxArtUrl: 'https://images.unsplash.com/photo-1518770660439-4636190af475?w=300&h=400&fit=crop',
25    viewerCount: 8932,
26    tags: ['Educational', 'Tech']
27  },
28  {
29    id: '3',
30    name: 'Just Chatting',
31    boxArtUrl: 'https://images.unsplash.com/photo-1519389950473-47ba0277781c?w=300&h=400&fit=crop',
32    viewerCount: 45123,
33    tags: ['IRL', 'Talk Show']
34  },
35  {
36    id: '4',
37    name: 'Music & Performing Arts',
38    boxArtUrl: 'https://images.unsplash.com/photo-1511379938547-c1f69419868d?w=300&h=400&fit=crop',
39    viewerCount: 6789,
40    tags: ['Music', 'Performance']
41  },
42  {
43    id: '5',
44    name: 'Art',
45    boxArtUrl: 'https://images.unsplash.com/photo-1460661419201-fd4cecdf8a8b?w=300&h=400&fit=crop',
46    viewerCount: 4321,
47    tags: ['Creative', 'Drawing']
48  },
49  {
50    id: '6',
51    name: 'Makers & Crafting',
52    boxArtUrl: 'https://images.unsplash.com/photo-1452860606245-08befc0ff44b?w=300&h=400&fit=crop',
53    viewerCount: 2156,
54    tags: ['DIY', 'Crafts']
55  }
56];
57
58export default function BrowsePage() {
59  const [activeTab, setActiveTab] = useState<'categories' | 'live'>('categories');
60
61  return (
62    <div className="min-h-screen bg-gray-950 text-white p-8">
63      <h1 className="text-3xl font-bold mb-6">Browse</h1>
64
65      {/* Tabs */}
66      <div className="flex gap-6 mb-8 border-b border-gray-800">
67        {[
68          { key: 'categories', label: 'Categories' },
69          { key: 'live', label: 'Live Channels' }
70        ].map(tab => (
71          <button
72            key={tab.key}
73            onClick={() => setActiveTab(tab.key as any)}
74            className={`pb-3 font-semibold ${
75              activeTab === tab.key
76                ? 'border-b-2 border-purple-500'
77                : 'text-gray-400 hover:text-white'
78            }`}
79          >
80            {tab.label}
81          </button>
82        ))}
83      </div>
84
85      {/* Categories Grid */}
86      {activeTab === 'categories' && (
87        <div className="grid grid-cols-6 gap-4">
88          {mockCategories.map(category => (
89            <div key={category.id} className="cursor-pointer group">
90              <div className="relative mb-2 overflow-hidden rounded">
91                <img
92                  src={category.boxArtUrl}
93                  alt={category.name}
94                  className="w-full aspect-[3/4] object-cover group-hover:scale-110 transition"
95                />
96                <div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black to-transparent p-2">
97                  <div className="text-xs text-gray-300">
98                    {category.viewerCount.toLocaleString()} viewers
99                  </div>
100                </div>
101              </div>
102              <h3 className="font-semibold text-sm mb-1">{category.name}</h3>
103              <div className="flex flex-wrap gap-1">
104                {category.tags.map(tag => (
105                  <span key={tag} className="text-xs bg-gray-800 px-2 py-0.5 rounded">
106                    {tag}
107                  </span>
108                ))}
109              </div>
110            </div>
111          ))}
112        </div>
113      )}
114    </div>
115  );
116}

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Que fait le pipeline CI/CD avec GitHub Actions décrit dans la leçon ?

  2. 2. Quel évènement déclenche le workflow Deploy (la section on:) ?

Tâches pratiques dans le jeu

  • Tri vertical

    Ordonne les étapes du job deploy dans le workflow :

  • Tri horizontal

    Ordonne la référence au token Vercel depuis secrets (une ligne) : ${{ secrets.VERCEL_TOKEN }}

Articles utiles