name: CI/CD on: push: jobs: # runs on branch pushes only ci: name: Run Tests if: startsWith(github.ref, 'refs/heads') runs-on: ubuntu-18.04 steps: - name: Checkout uses: actions/checkout@v2 - name: Setup Node.js uses: actions/setup-node@v1 with: node-version: 16 - name: Install dependencies run: npm ci - name: happy-path id: happy_path uses: ./ with: timeout_minutes: 1 max_attempts: 2 command: npm -v - uses: nick-invision/assert-action@v1 with: expected: true actual: ${{ steps.happy_path.outputs.total_attempts == '1' && steps.happy_path.outputs.exit_code == '0' }} - name: log examples uses: ./ with: command: node ./.github/scripts/log-examples.js timeout_minutes: 1 - name: sad-path (retry_wait_seconds) id: sad_path_wait_sec uses: ./ continue-on-error: true with: timeout_minutes: 1 max_attempts: 3 retry_wait_seconds: 15 command: npm install this-isnt-a-real-package-name-zzz - uses: nick-invision/assert-action@v1 with: expected: 3 actual: ${{ steps.sad_path_wait_sec.outputs.total_attempts }} - uses: nick-invision/assert-action@v1 with: expected: failure actual: ${{ steps.sad_path_wait_sec.outcome }} - uses: nick-invision/assert-action@v1 with: expected: 'Final attempt failed' actual: ${{ steps.sad_path_wait_sec.outputs.exit_error }} comparison: contains - name: new-command-on-retry id: new-command-on-retry uses: ./ with: timeout_minutes: 1 max_attempts: 3 command: node -e "process.exit(1)" new_command_on_retry: node -e "console.log('this is the new command on retry')" - name: on-retry-cmd id: on-retry-cmd uses: ./ continue-on-error: true with: timeout_minutes: 1 max_attempts: 3 command: node -e "process.exit(1)" on_retry_command: node -e "console.log('this is a retry command')" - name: retry_on_exit_code (with expected error code) id: retry_on_exit_code_expected uses: ./ continue-on-error: true with: timeout_minutes: 1 retry_on_exit_code: 2 max_attempts: 3 command: node -e "process.exit(2)" - uses: nick-invision/assert-action@v1 with: expected: failure actual: ${{ steps.retry_on_exit_code_expected.outcome }} - uses: nick-invision/assert-action@v1 with: expected: 3 actual: ${{ steps.retry_on_exit_code_expected.outputs.total_attempts }} - name: retry_on_exit_code (with unexpected error code) id: retry_on_exit_code_unexpected uses: ./ continue-on-error: true with: timeout_minutes: 1 retry_on_exit_code: 2 max_attempts: 3 command: node -e "process.exit(1)" - uses: nick-invision/assert-action@v1 with: expected: failure actual: ${{ steps.retry_on_exit_code_unexpected.outcome }} - uses: nick-invision/assert-action@v1 with: expected: 1 actual: ${{ steps.retry_on_exit_code_unexpected.outputs.total_attempts }} - name: on-retry-cmd (on-retry fails) id: on-retry-cmd-fails uses: ./ continue-on-error: true with: timeout_minutes: 1 max_attempts: 3 command: node -e "process.exit(1)" on_retry_command: node -e "throw new Error('This is an on-retry command error')" - name: sad-path (error) id: sad_path_error uses: ./ continue-on-error: true with: timeout_minutes: 1 max_attempts: 2 command: node -e "process.exit(1)" - uses: nick-invision/assert-action@v1 with: expected: 2 actual: ${{ steps.sad_path_error.outputs.total_attempts }} - uses: nick-invision/assert-action@v1 with: expected: failure actual: ${{ steps.sad_path_error.outcome }} - name: happy-path (continue_on_error) id: happy_path_continue_on_error uses: ./ with: command: node -e "process.exit(0)" timeout_minutes: 1 continue_on_error: true - name: sad-path (continue_on_error) id: sad_path_continue_on_error uses: ./ with: command: node -e "process.exit(33)" timeout_minutes: 1 continue_on_error: true - name: Verify continue_on_error returns correct exit code on success uses: nick-invision/assert-action@v1 with: expected: 0 actual: ${{ steps.happy_path_continue_on_error.outputs.exit_code }} - name: Verify continue_on_error exits with correct outcome on success uses: nick-invision/assert-action@v1 with: expected: success actual: ${{ steps.happy_path_continue_on_error.outcome }} - name: Verify continue_on_error returns correct exit code on error uses: nick-invision/assert-action@v1 with: expected: 33 actual: ${{ steps.sad_path_continue_on_error.outputs.exit_code }} - name: Verify continue_on_error exits with successful outcome when an error occurs uses: nick-invision/assert-action@v1 with: expected: success actual: ${{ steps.sad_path_continue_on_error.outcome }} - name: retry_on (timeout) fails early if error encountered id: retry_on_timeout_fail uses: ./ continue-on-error: true with: timeout_minutes: 1 max_attempts: 3 retry_on: timeout command: node -e "process.exit(2)" - uses: nick-invision/assert-action@v1 with: expected: 1 actual: ${{ steps.retry_on_timeout_fail.outputs.total_attempts }} - uses: nick-invision/assert-action@v1 with: expected: failure actual: ${{ steps.retry_on_timeout_fail.outcome }} - uses: nick-invision/assert-action@v1 with: expected: 2 actual: ${{ steps.retry_on_timeout_fail.outputs.exit_code }} - name: retry_on (error) id: retry_on_error uses: ./ continue-on-error: true with: timeout_minutes: 1 max_attempts: 2 retry_on: error command: node -e "process.exit(2)" - uses: nick-invision/assert-action@v1 with: expected: 2 actual: ${{ steps.retry_on_error.outputs.total_attempts }} - uses: nick-invision/assert-action@v1 with: expected: failure actual: ${{ steps.retry_on_error.outcome }} - uses: nick-invision/assert-action@v1 with: expected: 2 actual: ${{ steps.retry_on_error.outputs.exit_code }} # timeout tests (takes longer to run so run last) - name: sad-path (timeout) id: sad_path_timeout uses: ./ continue-on-error: true with: timeout_seconds: 15 max_attempts: 2 command: node -e "(async()=>await new Promise(r => setTimeout(r, 120000)))()" - uses: nick-invision/assert-action@v1 with: expected: 2 actual: ${{ steps.sad_path_timeout.outputs.total_attempts }} - uses: nick-invision/assert-action@v1 with: expected: failure actual: ${{ steps.sad_path_timeout.outcome }} - name: retry_on (timeout) id: retry_on_timeout uses: ./ continue-on-error: true with: timeout_seconds: 15 max_attempts: 2 retry_on: timeout command: node -e "(async()=>await new Promise(r => setTimeout(r, 120000)))()" - uses: nick-invision/assert-action@v1 with: expected: 2 actual: ${{ steps.retry_on_timeout.outputs.total_attempts }} - uses: nick-invision/assert-action@v1 with: expected: failure actual: ${{ steps.retry_on_timeout.outcome }} - name: retry_on (error) fails early if timeout encountered id: retry_on_error_fail uses: ./ continue-on-error: true with: timeout_seconds: 15 max_attempts: 2 retry_on: error command: node -e "(async()=>await new Promise(r => setTimeout(r, 120000)))()" - uses: nick-invision/assert-action@v1 with: expected: 1 actual: ${{ steps.retry_on_error_fail.outputs.total_attempts }} - uses: nick-invision/assert-action@v1 with: expected: failure actual: ${{ steps.retry_on_error_fail.outcome }} - uses: nick-invision/assert-action@v1 with: expected: 1 actual: ${{ steps.retry_on_error_fail.outputs.exit_code }} - name: sad-path (timeout minutes) id: sad_path_timeout_minutes uses: ./ continue-on-error: true with: timeout_minutes: 1 max_attempts: 2 command: node -e "(async()=>await new Promise(r => setTimeout(r, 120000)))()" - uses: nick-invision/assert-action@v1 with: expected: 2 actual: ${{ steps.sad_path_timeout.outputs.total_attempts }} - uses: nick-invision/assert-action@v1 with: expected: failure actual: ${{ steps.sad_path_timeout.outcome }} - name: sad-path (wrong shell for OS) id: wrong_shell uses: ./ continue-on-error: true with: timeout_minutes: 1 max_attempts: 2 shell: cmd command: 'dir' - uses: nick-invision/assert-action@v1 with: expected: 2 actual: ${{ steps.wrong_shell.outputs.total_attempts }} - uses: nick-invision/assert-action@v1 with: expected: failure actual: ${{ steps.wrong_shell.outcome }} ci_windows: name: Run Windows Tests if: startsWith(github.ref, 'refs/heads') runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v2 - name: Setup Node.js uses: actions/setup-node@v1 with: node-version: 16 - name: Install dependencies run: npm ci - name: Powershell test uses: ./ with: timeout_minutes: 1 max_attempts: 2 shell: powershell command: Get-ComputerInfo - name: CMD.exe test uses: ./ with: timeout_minutes: 1 max_attempts: 2 shell: cmd command: echo %PATH% - name: Python test uses: ./ with: timeout_minutes: 1 max_attempts: 2 shell: python command: print('1', '2', '3') - name: Multi-line multi-command Test uses: ./ with: timeout_minutes: 1 max_attempts: 2 command: | Get-ComputerInfo Get-Date - name: Multi-line single-command Test uses: ./ with: timeout_minutes: 1 max_attempts: 2 shell: cmd command: >- echo "this is a test" # runs on push to master only cd: name: Publish Action needs: ci if: github.ref == 'refs/heads/master' runs-on: ubuntu-18.04 steps: - name: Checkout uses: actions/checkout@v2 - name: Setup Node.js uses: actions/setup-node@v1 with: node-version: 16 - name: Install dependencies run: npm ci - name: Release id: semantic uses: cycjimmy/semantic-release-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Tag run: git tag -f v${MAJOR_VERSION} && git push -f origin v${MAJOR_VERSION} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} MAJOR_VERSION: ${{ steps.semantic.outputs.new_release_major_version }}