2023-08-24 06:06:51 +03:00
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package actions
import (
"context"
"fmt"
"time"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
2024-01-31 17:55:12 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2023-09-07 05:25:46 +03:00
"code.gitea.io/gitea/models/unit"
2023-08-24 06:06:51 +03:00
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
webhook_module "code.gitea.io/gitea/modules/webhook"
"github.com/nektos/act/pkg/jobparser"
)
// StartScheduleTasks start the task
func StartScheduleTasks ( ctx context . Context ) error {
return startTasks ( ctx )
}
// startTasks retrieves specifications in pages, creates a schedule task for each specification,
// and updates the specification's next run time and previous run time.
// The function returns an error if there's an issue with finding or updating the specifications.
func startTasks ( ctx context . Context ) error {
// Set the page size
pageSize := 50
// Retrieve specs in pages until all specs have been retrieved
now := time . Now ( )
for page := 1 ; ; page ++ {
// Retrieve the specs for the current page
specs , _ , err := actions_model . FindSpecs ( ctx , actions_model . FindSpecOptions {
ListOptions : db . ListOptions {
Page : page ,
PageSize : pageSize ,
} ,
Next : now . Unix ( ) ,
} )
if err != nil {
return fmt . Errorf ( "find specs: %w" , err )
}
2023-10-11 07:24:07 +03:00
if err := specs . LoadRepos ( ctx ) ; err != nil {
2023-09-07 05:25:46 +03:00
return fmt . Errorf ( "LoadRepos: %w" , err )
}
2023-08-24 06:06:51 +03:00
// Loop through each spec and create a schedule task for it
for _ , row := range specs {
// cancel running jobs if the event is push
if row . Schedule . Event == webhook_module . HookEventPush {
// cancel running jobs of the same workflow
2024-03-21 10:01:35 +03:00
if err := actions_model . CancelPreviousJobs (
2023-08-24 06:06:51 +03:00
ctx ,
row . RepoID ,
row . Schedule . Ref ,
row . Schedule . WorkflowID ,
2024-01-13 00:50:38 +03:00
webhook_module . HookEventSchedule ,
2023-08-24 06:06:51 +03:00
) ; err != nil {
2024-03-21 10:01:35 +03:00
log . Error ( "CancelPreviousJobs: %v" , err )
2023-08-24 06:06:51 +03:00
}
}
2024-04-01 16:48:14 +03:00
if row . Repo . IsArchived {
// Skip if the repo is archived
continue
}
2024-01-31 17:55:12 +03:00
cfg , err := row . Repo . GetUnit ( ctx , unit . TypeActions )
if err != nil {
if repo_model . IsErrUnitTypeNotExist ( err ) {
// Skip the actions unit of this repo is disabled.
continue
}
return fmt . Errorf ( "GetUnit: %w" , err )
}
if cfg . ActionsConfig ( ) . IsWorkflowDisabled ( row . Schedule . WorkflowID ) {
2023-09-07 05:25:46 +03:00
continue
}
2023-08-24 06:06:51 +03:00
if err := CreateScheduleTask ( ctx , row . Schedule ) ; err != nil {
log . Error ( "CreateScheduleTask: %v" , err )
return err
}
// Parse the spec
schedule , err := row . Parse ( )
if err != nil {
log . Error ( "Parse: %v" , err )
return err
}
// Update the spec's next run time and previous run time
row . Prev = row . Next
row . Next = timeutil . TimeStamp ( schedule . Next ( now . Add ( 1 * time . Minute ) ) . Unix ( ) )
if err := actions_model . UpdateScheduleSpec ( ctx , row , "prev" , "next" ) ; err != nil {
log . Error ( "UpdateScheduleSpec: %v" , err )
return err
}
}
// Stop if all specs have been retrieved
if len ( specs ) < pageSize {
break
}
}
return nil
}
// CreateScheduleTask creates a scheduled task from a cron action schedule.
// It creates an action run based on the schedule, inserts it into the database, and creates commit statuses for each job.
func CreateScheduleTask ( ctx context . Context , cron * actions_model . ActionSchedule ) error {
// Create a new action run based on the schedule
run := & actions_model . ActionRun {
Title : cron . Title ,
RepoID : cron . RepoID ,
OwnerID : cron . OwnerID ,
WorkflowID : cron . WorkflowID ,
TriggerUserID : cron . TriggerUserID ,
Ref : cron . Ref ,
CommitSHA : cron . CommitSHA ,
Event : cron . Event ,
EventPayload : cron . EventPayload ,
2024-01-13 00:50:38 +03:00
TriggerEvent : string ( webhook_module . HookEventSchedule ) ,
2023-09-08 18:01:19 +03:00
ScheduleID : cron . ID ,
2023-08-24 06:06:51 +03:00
Status : actions_model . StatusWaiting ,
}
2024-04-23 21:55:25 +03:00
vars , err := actions_model . GetVariablesOfRun ( ctx , run )
if err != nil {
log . Error ( "GetVariablesOfRun: %v" , err )
return err
}
2023-08-24 06:06:51 +03:00
// Parse the workflow specification from the cron schedule
2024-04-23 21:55:25 +03:00
workflows , err := jobparser . Parse ( cron . Content , jobparser . WithVars ( vars ) )
2023-08-24 06:06:51 +03:00
if err != nil {
return err
}
// Insert the action run and its associated jobs into the database
if err := actions_model . InsertRun ( ctx , run , workflows ) ; err != nil {
return err
}
// Return nil if no errors occurred
return nil
}