import { BuildResult } from './types/GodotExport' ; import * as semver from 'semver' ; import * as core from '@actions/core' ; import { BASE_VERSION , GENERATE_RELEASE_NOTES , ARCHIVE_SINGLE_RELEASE_OUTPUT } from './constants' ; import { getRepositoryInfo , getGitHubClient } from './github' ; import { exec } from '@actions/exec' ; import { ExecOptions } from '@actions/exec/lib/interfaces' ; import path from 'path' ; import * as fs from 'fs' ; import { zipBuildResults } from './file' ; import { OctokitResponse } from '@octokit/types' ; async function createRelease ( buildResults ) { if ( buildResults . some ( x => ! x . archivePath ) ) { await zipBuildResults ( buildResults ) ; } core . startGroup ( 'Creating release' ) ; await createGitHubRelease ( buildResults ) ; core . endGroup ( ) ; } async function createGitHubRelease ( buildResults ) { const version = await getAndCheckNewVersion ( ) ; const versionStr = `v${ version . format ( ) }` ; core . info ( `Using release version ${ versionStr }` ) ; const repoInfo = getRepositoryInfo ( ) ; const body = GENERATE_RELEASE_NOTES ? await getReleaseBody ( ) : undefined ; const response = await getGitHubClient ( ) . rest . repos . createRelease ( { owner : repoInfo . owner , tag_name : versionStr , repo : repoInfo . repository , name : versionStr , target_commitish : process . env . GITHUB_SHA , body , } ) ; const promises = [ ] ; for ( const buildResult of buildResults ) { promises . push ( upload ( response , buildResult ) ) ; } await Promise . all ( promises ) ; } async function getAndCheckNewVersion ( ) { const newVersion = await getNewVersion ( ) ; if ( ! newVersion ) { const message = 'Could not establish a version for the release. Please check that "base_version" is a https://semver.org/ style string.' ; core . setFailed ( message ) ; throw new Error ( message ) ; } return newVersion ; } async function getNewVersion ( ) { const latestTag = await getLatestReleaseTagName ( ) ; const parsedBaseVersion = semver . parse ( BASE_VERSION ) ; if ( latestTag ) { let latest = semver . parse ( latestTag ) ; if ( latest && parsedBaseVersion ) { if ( semver . gt ( parsedBaseVersion , latest ) ) { latest = semver . parse ( parsedBaseVersion ) ; } else { latest = latest ?. inc ( 'patch' ) ?? null ; } return latest ; } } return parsedBaseVersion ; } async function getLatestReleaseTagName ( ) { try { const repoInfo = getRepositoryInfo ( ) ; const release = await getGitHubClient ( ) . rest . repos . getLatestRelease ( { owner : repoInfo . owner , repo : repoInfo . repository , } ) ; return release . data . tag_name ; } catch ( e ) { core . info ( 'No latest release found' ) ; } return undefined ; } async function getReleaseBody ( ) { core . info ( 'Generating release notes' ) ; const delimiter = '---delimiter---' ; const latestTag = await getLatestReleaseTagName ( ) ; const args = [ 'log' ] ; if ( latestTag ) { args . push ( `${ latestTag }..HEAD` ) ; } args . push ( `--format=%B%H${ delimiter }` ) ; let body = '' ; const options = { ignoreReturnCode : true , listeners : { stdout : ( data ) => { body += data . toString ( ) ; } , } , } ; await exec ( 'git' , args , options ) ; const changes = body . trim ( ) . split ( delimiter ) ; changes . reverse ( ) ; const formattedChanges = changes . map ( change => change . trim ( ) ) . filter ( change => change . length ) . map ( change => `- ${ change }` ) ; return formattedChanges . join ( '\n' ) ; } async function upload ( response , buildResult ) { if ( ! buildResult . archivePath ) { const message = 'Attempted to upload a non-existent archive.' ; core . setFailed ( message ) ; throw new Error ( message ) ; } let fileToUpload = buildResult . archivePath ; if ( ! ARCHIVE_SINGLE_RELEASE_OUTPUT && buildResult . directoryEntryCount === 1 ) { fileToUpload = buildResult . executablePath ; } core . info ( `Uploading ${ fileToUpload }` ) ; const content = fs . readFileSync ( fileToUpload ) ; const repoInfo = getRepositoryInfo ( ) ; await getGitHubClient ( ) . rest . repos . uploadReleaseAsset ( { data : content , headers : { 'Content-Type' : 'application/zip' , 'Content-Length' : content . byteLength } , name : path . basename ( fileToUpload ) , url : response . data . upload_url , owner : repoInfo . owner , repo : repoInfo . repository , release_id : response . data . id , } ) ; } export { createRelease } ;