1import Apify from 'apify';
2
3const { utils: { log, sleep } } = Apify;
4
5Apify.main(async () => {
6
7    const client = Apify.newClient();
8    const { items: actors } = await client.actors().list();
9    const { batchType, actorNameContains, actorIds } = await Apify.getInput();
10
11    let batchTypeDescription = "";
12    let targetActors = [];
13    let actorCount = 0;
14    let totalBuildsFinished = 0;
15    let requestsCount = 0;
16
17    let results = {
18        "builds": [],
19        "stats": {
20            "total": 0,
21            "failed": 0,
22            "succeeded": 0,
23            "requests": 0
24        }
25    };
26
27
28    async function prepTargetActors() {
29        for (const item in actors) {
30            if (batchType == "actorNameContains" && actors[item].name.includes(actorNameContains)) {
31                targetActors.push(actors[item]);
32                batchTypeDescription = "matching part of the actor name.";
33            }
34            else if (batchType == "actorIds" && actorIds.includes(actors[item].id)) {
35                targetActors.push(actors[item]);
36                batchTypeDescription = "matching selected actor ids.";
37            }
38            else if (batchType == "all") {
39                targetActors.push(actors[item]);
40                batchTypeDescription = "for all actors in the account.";
41            };
42        };
43        log.info(`Starting builds ${batchTypeDescription}`);
44        log.info('–––––––––––––––––––––––––––––––––––––––––');
45    }
46
47
48    async function buildActors(targetActors) {
49        let actorsInProgress = [];
50        for (const item in targetActors) {
51            actorCount++;
52            await sleep(1000);
53            const { id: actorId, name: actorName } = targetActors[item];
54            const actor = client.actor(actorId);
55
56            try {
57                const startBuild = await actor.build('0.0');
58                requestsCount++;
59
60                log.info(`${actorCount}.`);
61                log.info(`actor name: ${actorName}`);
62                log.info(`build id:   ${startBuild.id}`);
63                log.info(`started at: ${startBuild.startedAt}`);
64                log.info(`status:     ${startBuild.status}`);
65                log.info('–––––––––––––––––––––––––––––––––––––––––');
66
67                actorsInProgress.push(targetActors[item]);
68
69            } catch (error) {
70                actorCount--;
71
72                log.warning(`skipping actor ${actorName} due to ${error.type}.`);
73                log.warning(`actor id: ${actorId}`);
74                log.info('–––––––––––––––––––––––––––––––––––––––––');
75            }
76        }
77        log.info(`builds started for ${actorCount} actors.`);
78        log.info('waiting for builds to finish...');
79        log.info('–––––––––––––––––––––––––––––––––––––––––');
80
81        return actorsInProgress;
82    };
83
84
85    async function checkBuilds(targetActor) {
86        const actor = client.actor(targetActor.id);
87        const { id: actorId, name: actorName, buildtag: actorBuildTag } = await actor.get();
88        requestsCount++;
89
90        let buildFinshed = false;
91        while (!buildFinshed) {
92            await sleep(delay);
93            requestsCount++;
94            const { items: actorBuilds } = await actor.builds().list({ 'desc': true });
95            const buildInProgress = actorBuilds[0];
96
97            let result = { ...buildInProgress, actorId, actorName, actorBuildTag };
98
99            if (buildInProgress.status == 'RUNNING') {
100                buildFinshed = false;
101
102            } else if (buildInProgress.status == 'SUCCEEDED') {
103                results.stats.total++;
104                results.stats.succeeded++;
105
106                buildFinshed = true;
107                totalBuildsFinished++;
108                results.builds.push(result);
109
110                log.info(`${totalBuildsFinished} of ${actorCount}`);
111                log.info(`actor name:  ${actorName}`);
112                log.info(`finished at: ${buildInProgress.finishedAt}`);
113                log.info(`status:      ${buildInProgress.status}`);
114                log.info('–––––––––––––––––––––––––––––––––––––––––');
115
116            } else if (buildInProgress.status == 'FAILED') {
117                results.stats.total++;
118                results.stats.failed++;
119
120                buildFinshed = true;
121                totalBuildsFinished++;
122                results.builds.push(result);
123
124                log.info(`${totalBuildsFinished} of ${actorCount}`);
125                log.error(`actor name:  ${actorName}`);
126                log.error(`finished at: ${buildInProgress.finishedAt}`);
127                log.error(`status:      ${buildInProgress.status}`);
128                log.info('–––––––––––––––––––––––––––––––––––––––––');
129            }
130        }
131    }
132
133    async function startChecks(actorsInProgress) {
134        for (const item in actorsInProgress) {
135            checkBuilds(actorsInProgress[item]);
136        }
137        while (totalBuildsFinished != actorsInProgress.length) {
138            await sleep(delay);
139        }
140        results.stats.requests = requestsCount;
141    }
142
143
144    await prepTargetActors();
145    let actorsInProgress = await buildActors(targetActors.slice(0));
146    let delay = (actorCount > 0) ? 10000 : 0;
147    await sleep(delay);
148    await startChecks(actorsInProgress);
149
150    log.info('Done.');
151    log.info(`total builds requested:  ${results.stats.total}`);
152    log.info(`total builds successful: ${results.stats.succeeded}`);
153    log.info(`total builds failed:     ${results.stats.failed}`);
154    log.info(`total API calls:         ${results.stats.requests}`);
155
156    const store = await Apify.openKeyValueStore();
157    await store.setValue('STATS', results.stats);
158    await Apify.pushData(results.builds);
159});