TestProject Forum

Upload APK and run JOB via API with node script for CI

Hey guys,

I didnt found what i needed around so i wrote this script using node.js and the Test Project API
I made this script to use it inside Gitlab CI
Hope it can help someone else :slight_smile:

const Axios = require('axios')
const fs = require('fs')
const args = require('yargs').argv

const HEARTBEAT_INTERVAL = 5000 // check job state every 5 sec

const start = async () => {
  const testProjectAPI = 'https://api.testproject.io'

  const { API_KEY, projectID, applicationID, jobID, APKpath, jobTimeout } = args

  if (
    !API_KEY ||
    !projectID ||
    !applicationID ||
    !jobID ||
    !APKpath ||
    !jobTimeout
  ) {
    console.log('----------------------------------')
    console.log('SCRIPT ERROR - Missing Arguments')
    console.log('Required Arguments')
    console.log(
      '--API_KEY --projectID --applicationID --jobID --APKpath --jobTimeout',
    )
    console.log('----------------------------------')
    process.exit(1)
  }

  const axios = Axios.create({
    headers: {
      common: {
        Authorization: API_KEY,
      },
    },
  })

  const uploadLinkForApk = await axios
    .get(
      testProjectAPI +
        `/v2/projects/${projectID}/applications/${applicationID}/file/upload-link`,
    )
    .catch((err) => {
      throw new Error('Error fetching upload link : ' + err.message)
    })

  const file = fs.readFileSync(APKpath)

  const uploadApk = await Axios.create({
    maxBodyLength: Infinity,
    headers: {
      'Content-Type': 'application/vnd.android.package-archive',
    },
  })
    .put(uploadLinkForApk.data.url, file)
    .then(() => console.log('APK successfully uploaded on s3'))
    .catch((err) => {
      throw new Error('Error uploading APK on s3 : ' + err.message)
    })

  const checkUploadedApk = await axios
    .post(
      testProjectAPI +
        `/v2/projects/${projectID}/applications/${applicationID}/file`,
      {
        fileName: APKpath.split('/')[APKpath.split('/').length - 1],
      },
    )
    .then(() => console.log('APK successfully uploaded on TestProject'))
    .catch((err) => {
      throw new Error('Error checking APK on TestProject : ' + err.message)
    })

  const executeJob = await axios
    .post(testProjectAPI + `/v2/projects/${projectID}/jobs/${jobID}/run`)
    .then(() => console.log('Executing Test Project job ...'))
    .catch((err) => {
      throw new Error(
        'Error executing Test Project job : ' +
          err.message +
          ' - ' +
          err.response.headers.message,
      )
    })

  const executionID = executeJob.data.id

  const reportURL = `https://app.testproject.io/#/reports/projects/${projectID}/jobs/${jobID}/execution/${executionID}`

  const checkForReportInterval = setInterval(async () => {
    const executionState = await axios
      .get(
        testProjectAPI +
          `/v2/projects/${projectID}/jobs/${jobID}/executions/${executionID}/state`,
      )
      .catch((err) => {
        console.log(
          'Heartbeat : Error when checking execution state : ' + err.message,
        )
      })

    switch (executionState?.data?.state) {
      case 'Passed':
        clearInterval(checkForReportInterval)
        console.log('JOB SUCCESSFULLY PASSED', `check report at ${reportURL}`)
        process.exit(0)
        break
      case 'Failed':
        clearInterval(checkForReportInterval)
        console.log('JOB FAILED', `check report at ${reportURL}`)
        process.exit(1)
        break
      default:
        console.log('Heartbeat : Execution still in progress ...')
    }
  }, HEARTBEAT_INTERVAL)

  setTimeout(() => {
    if (checkForReportInterval) {
      clearInterval(checkForReportInterval)
      console.log('HEARTBEAT TIMEOUT', `check job report at ${reportURL}`)
      process.exit(1)
    }
  }, jobTimeout)
}

start().catch((err) => {
  console.log(err.message)
  process.exit(1)
})