3

I'm trying to write a Python script that starts a subprocess to run an Azure CLI command once the file is executed.

When I run locally, I run:

az pipelines create --name pipeline-from-cli --repository https://github.com/<org>/<project> --yml-path <path to pipeline>.yaml --folder-path _poc-area

I get prompted for an input which looks like:

Which service connection do you want to use to communicate with GitHub?
 [1] Create new GitHub service connection
 [2] <my connection name>
 [3] <org name>
Please enter a choice [Default choice(1)]:

I can type in 2 and press enter then my pipeline is successfully created in Azure DevOps. I would like to run this command being dynamically entered when prompted.

So far I have tried:

import subprocess

cmd = 'az pipelines create --name pipeline-from-cli --repository https://github.com/<org>/<project> --yml-path <path to pipeline>.yaml --folder-path _poc-area
cmd = cmd.split()

subprocess.run(cmd, shell=True)

This will run in the exact same way as when I try to run it locally.

Try to follow answers from here I have also tried:

p = subprocess.run(cmd, input="1", capture_output=True, text=True, shell=True)
print(p)

Which gives me an error saying raise NoTTYException(error_msg)\nknack.prompting.NoTTYException.

Is there a way where I can execute this Python script, and it will run the Azure CLI command then enter 2 when prompted without any manually intervention?

agw2021
  • 266
  • 2
  • 22

2 Answers2

0

You are trying to solve the wrong problem. az pipeline create takes a --service-connection parameter. You don't need to respond to the prompt, you can provide the service connection value on the command line and skip the prompt entirely.

Daniel Mann
  • 57,011
  • 13
  • 100
  • 120
  • When I add the `--service-connection` parameter with the exact same service connection value that shows up in the prompt when running locally, I get an error saying `Could not create service hooks subscription. The repository does not reference a service connection.` – agw2021 Jan 10 '23 at 18:01
0

IMHO, Daniel is right, you're not supposed to deal with stdin in your program. Nevertheless, if you really need to, you should use pexpect package, which basically opens a process, waits for given output, and then sends input to the process' stdin.

Here's a basic example:

import pexpect
from pexpect.popen_spawn import PopenSpawn

cmd = 'az pipelines create --name pipeline-from-cli --repository https://github.com/<org>/<project> --yml-path <path to pipeline>.yaml --folder-path _poc-area'
child = pexpect.popen_spawn.PopenSpawn('cmd', timeout=1)
child.expect ('.*Please enter a choice.*')
child.sendline ('2')
# child.interact()     # Give control of the child to the user.

Have a look at pexpect documentation for more details. MS Windows support is available since v4.0.

Another archaic solution would be to use subprocess the following way, emulating basically what expect would do:

import subprocess
from time import sleep

p = subprocess.Popen(azure_command, stdout=PIPE, stdin=PIPE, stderr=STDOUT)
sleep(.5)
stdout = p.communicate(input=b'2\n')[0]
print(stdout.decode())

Still, best solution is to use non-interactive mode of most CLI programs.

Orsiris de Jong
  • 2,819
  • 1
  • 26
  • 48
  • Sorry for the late response. As I am on a Windows machine, using the `pexpect.spawn()` command gives me an error saying `AttributeError: module 'pexpect' has no attribute 'spawn'`. When I use the alternative way I get: ` File "C:\Python381\lib\subprocess.py", line 1307, in _execute_child hp, ht, pid, tid = _winapi.CreateProcess(executable, args, FileNotFoundError: [WinError 2] The system cannot find the file specified` – agw2021 Jan 25 '23 at 21:46
  • Too bad bounty is gone. What version of pexpect did you install ? As for the alternative, depending on your command, you will have to add `shell=True` for PATHS variable to exist. Also try to run with UAC for sake of sanity. – Orsiris de Jong Jan 26 '23 at 01:42
  • Updated my example above, just tested it using`cmd.exe` as command then sending `ipconfig`. Works good. – Orsiris de Jong Jan 26 '23 at 01:50