Windows command line variable in Git command - windows

What specific syntax needs to be changed in the windows command line commands below in order for git remote add origin %repoWithToken% to resolve to the intended valid URL?
COMMANDS THAT ARE FAILING:
The following commands are run in a pwsh shell on a windows-latest GitHub runner.
set repoWithToken="https://"$GIT_PAT"#github.com/accountName/repoName.git"
git init
git remote add origin %repoWithToken%
ERROR MESSAGE:
The following error message is given by the GitHub windows-latest runner when the above code is run:
fatal: '%repoWithToken%' does not appear to be a git repository
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
Error: Process completed with exit code 1.
The answer can just be simple windows command line command. No need for any fancy PowerShell.
Also, $GIT_PAT is correct GitHub syntax, though it is possible that the concatenation in set repoWithToken="https://"$GIT_PAT"#github.com/accountName/repoName.git" might need to be done differently in the code above. This is in the process of being translated from Bash.

Building on Olaf's helpful comments:
set <varName>=<value is used in cmd.exe for assigning variables; while in PowerShell set is a built-in alias for Set-Variable, the latter has very different syntax.
More importantly, its use is rarely needed, because variables are assigned as $<varName> = <value>
PowerShell uses the same syntax on setting and getting variable values, $<varName>; thus, after having assigned to a variable named repoWithToken with $repoWithToken = <value>, you also refer to its value later with $repoWithToken (by contrast, %repoWithToken% is again cmd.exe syntax).
Assuming that GIT_PAT is the name of an environment variable, you must refer to it as $env:GIT_PAT in PowerShell variable (with explicit name delineation: ${env:GIT_PAT})
Unlike Bash (and POSIX-compatible shells in general), PowerShell only allows you to compose a single string from a mix of quoted and unquoted tokens if the first token is unquoted.
Something like "https://"$GIT_PAT"#github.com/accountName/repoName.git" therefore doesn't work as a single string argument, because its first token is quoted, causing PowerShell to break it into two arguments in this case.
Since string interpolation is needed here in order to replace ${env:GIT_PAT} with its value, simply enclose the entire value in "...", i.e. make it an expandable string
Therefore:
$repoWithToken = "https://${env:GIT_PAT}#github.com/accountName/repoName.git"
git init
git remote add origin $repoWithToken

Related

Creating a GitHub Action which runs a Powershell script on a Windows host

My GitHub Actions workflow "runs-on" windows-latest. I want a custom Action which executes a PowerShell (core or legacy is fine) script. I have a parallel action that runs on Linux and MacOS. So, my .github/actions/install-tf-win directory contains this action.yml
name: install_tf_win
description: installs Terraform/TerraGrunt for Windows
runs:
using: "composite"
steps:
- run: install-tf-win\install-tf-win.ps1
shell: pwsh
The directory also contains install-tf-win.ps1. I have tried all sorts of variations on that run statement. Starting with "&" and without, variations in paths used with forwards and backwards slashes. I originally started with $GITHUB_ACTION_PATH/install-tf-win.ps1 (works for Linux/MacOS), however it seemed that GITHUB_ACTION_PATH was getting evaluated to be an empty string and then there were complaints about /install-tf-win.ps1 not being found. I tried both pwsh and powershell for the shell key value.
The form shown above results in this error:
Run ./.github/actions/install-tf-win
install-tf-win\install-tf-win.ps1: D:\a\_temp\c1d3d7fa-074b-4f90-ade0-799dcebd84ec.ps1:2
Line |
2 | install-tf-win\install-tf-win.ps1
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| The module 'install-tf-win' could not be loaded. For more information, run 'Import-Module
| install-tf-win'.
I can obviously code my way around this by just putting the PowerShell statements in a step. But, the documentation suggests this should work. https://docs.github.com/en/free-pro-team#latest/actions/creating-actions/metadata-syntax-for-github-actions#runsstepsshell .
So, how do I get this to work, please?
The error message implies that you cannot refer to your script with a relative path:
The command is passed to pwsh, PowerShell [Core]'s CLI, via its -Command (-c) parameter, which interprets the install-tf-win part of
install-tf-win\install-tf-win.ps1 as a module name rather than as a subdirectory in the absence of an actual subdirectory by that name on Windows[1], so the implication is that such a path doesn't exist.
The linked documentation, suggests that you need an absolute path, based on the GITHUB_ACTION_PATH environment variable, which in PowerShell must be referenced as $env:GITHUB_ACTION_PATH (untested):
# ...
- run: '& $env:GITHUB_ACTION_PATH/install-tf-win/install-tf-win.ps1'
shell: pwsh
Note:
The need to use &, the call operator, which is a syntactic necessity due to the script path containing a(n environment-)variable reference; the same would apply if the path were quoted - see this answer for background information.
Since & is a metacharacter in YAML when used unquoted at the start of a value, the entire string is quoted. Single-quoting ('...') is employed in this case, so that YAML doesn't interpret the contents of the string up front.
As an aside: The implication of '...'-quoting working (as confirmed by Kevin, the OP) is that when pwsh -c is ultimately called on Windows, the string's content is (properly) double-quoted ("..."), because PowerShell's CLI only recognizes " as having syntactic function for command-line argument parsing. By contrast, a '...'-quoted -c argument would be interpreted as a verbatim string rather than as a command, causing its content to be simply echoed.
[1] How PowerShell interprets a path such as foo\bar.ps1 when executed as a command, as of PowerShell 7.1
Interpreted as a command - both inside a PowerShell session and via the -Command / -c parameter of the PowerShell CLI, as used by GitHub Actions - the form foo\bar.ps1 is ambiguous:
It could refer to a module named foo, and its bar.ps1 command (even though module commands don't have .ps1 name extensions).
It could refer to a subdirectory foo and file bar.ps1 in it.
This applies to Windows only:
PowerShell first interprets the path as a file-system path.
If the path doesn't exist, it falls back to interpreting it as a module-command reference.
On Unix-like platforms - even though PowerShell generally allows you to use \ and / interchangeably as the path separator on all supported platforms - this particular path form is always interpreted as a module reference; in other words: you cannot use this syntax form to invoke a script this way (see below).
This surprising inconsistency is discussed in GitHub issue #14307.
There are two ways to avoid this ambiguity, which work on all supported platforms; the following cause PowerShell to unequivocally treat the path as file-system script path:
Use / instead of \: foo/bar.ps1
Prefix the path with .\ (or ./): .\foo\bar.ps1
(Of course, you could also use a full path.)
Note that when the -File parameter of PowerShell's is used (rather than -Command / -c), this ambiguity doesn't arise, as the argument is then always considered a (potentially relative) file-system path, even on Unix-like platforms, irrespective of whether you use \ or /.

How to add the current git branch to the existing bash prompt

I'm trying to modify my bash prompt to include the current git branch. This is complicated by the fact that there is already a set of rules that determines what the prompt might be - whether it includes color text, whether the user is on xterm etc. ... so what I really want is to be able to combine the string representing the git branch, colors and all, with the previously set prompt.
But I can't even get the most basic implementation to work. The following includes several of my attempts as I try to simplify the script to eliminate possible problems.
# Add current git branch, if any
parse_git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
}
#PS1="\[\e[34m\]\$(parse_git_branch)\[\e[00m\]$PS1 "
#PS1 = "\$(parse_git_branch) $PS1 "
#PS1 = "\$(parse_git_branch) "
#PS1 = "$(parse_git_branch) "
PS1 = $(parse_git_branch)
Essentially they all produce the same message:
PS1: command not found
I'm sure I am missing something simple. Can anyone tell me what it is?
The error you get is because of the spaces surrounding =, as bash attempts evaluates PS1 as a command, and fails.
You can fix it by just removing the spaces. Here is a sample prompt that prints the current user and directory, along with the prompt:
export PS1='[\u#\h] \W :: $(parse_git_branch)> '
Note the single quotes - if you instead use double quotes, the parse_git_branch will be evaluated and will not update on every prompt. As an alternative to single quotes, you can escape the $ if you prefer.
If you want to update your existing prompt to also have the git branch, you can print the current value of the PS1 environment variable and modify it to suit your needs, finally adding the modified version in say your .bashrc file.
In case you're willing to use an existing solution, there's a Git prompt function already included in many Linux distros. How to use:
PS1=…'$(__git_ps1 " (%s)")'…
The mixed quotes are intentional, and the single quotes are necessary to make this run every time the prompt is displayed. Replace the ellipses with the rest of the prompt, such as '\$ '. If __git_ps1 isn't available out of the box see the full code for a cross-platform solution (works on at least Ubuntu and Arch Linux; should work on recent NixOS).
The " (%s)" part is the format string, that is, a space, open parenthesis (because I want to keep this info separate from the rest of the prompt), the prompt string, and close parenthesis. The %s is replaced by a repository state string, by default just the branch name. See the source code for options and their meanings.

Passing an environment variable to a shell script from Fastlane

I'm running Fastlane (a continuous build tool for iOS) in order to execute a custom shell script for decrypting a file.
This is the command.
sh "./decrypt.sh ENV['ENCRYPTION_P12']"
I cannot figured out a way to pass the environment variable to that script. Obviously, if I hardcode the pwd into the script, it works correctly.
sh "./decrypt.sh mypwd"
Any suggestions?
Expanding From Within The Immediate Shell
Assuming that sh, here, is a fastlane command that invokes a shell command with the given argument as script text:
# as a fastlane directive
sh './decrypt.sh "$ENCRYPTION_P12"'
Note that if this were being literally invoked as a command line for /bin/sh, it would need a -c argument:
# in other contexts
sh -c './decrypt.sh "$ENCRYPTION_P12"'
Note that this absolutely depends on ENCRYPTION_P12 being an environment variable -- that is, exported to the environment by the system by which it was set.
Expanding from Within The Invoked Script
That said, if it is an environment variable, you have a better option: Just use it.
That is, inside decrypt.sh, you can refer to "$ENCRYPTION_P12" without needing to set it explicitly, as the shell implicitly imports all environment variables as shell variables -- and they're passed down to child processes without any explicit actions needed.
Things to Avoid: Shell Injection Attacks
Finally, an aside: The dangerous way to do this would have been something like:
# INSECURE: DO NOT DO THIS
sh "./decrypt.sh #{ENV['ENCRYPTION_P12']}"
or
# STILL INSECURE
sh "./decrypt.sh \"#{ENV['ENCRYPTION_P12'}\""
or
# STILL INSECURE
sh "./decrypt.sh '#{ENV['ENCRYPTION_P12'}'"
...thereby substituting the value into your generated string at the Ruby level. This is dangerous, however, as that string is parsed as code -- meaning that contents of ENCRYPTION_P12 could then be leveraged in shell attacks.
For instance, consider the case (given below in bash syntax):
# this will make any of the above do Very Evil Things
ENCRYPTION_P12=$'$(rm -rf ~)\'$(rm -rf ~)\''
...for which both rms will execute if directly substituted into generated shell script (as opposed to expanded during parameter expansion -- '${foo}' -- which takes place after the expansion phases which make this dangerous have already passed).
The fastlane specific answer is https://docs.fastlane.tools/advanced/#shell-values
or, from within your Fastfile:
decrypted = sh("./decrypt" ENV[ENCRYPTION_P12])

Run simple programme using unix shell

I'm new to unix and its developing. In my new.sh script I wrote
$USERNAME=user
$PASSWORD=sekrit
echo $USERNAME
and ran new.sh using bash new.sh
But I get the following errors
new.sh: line 1: =user: command not found
new.sh: line 2: =sekrit: command not found
How do I run that command and print the username variable in terminal?
USERNAME is the name of the variable. $USERNAME is the replacement (aka contents, aka value). Since USERNAME is empty, you effectively try to run a command named =user, which is what the error message tells you.
Remove the $ from $USERNAME=... and it will work.
As Jens notes in his answer, the problem is that an assignment to a variable is not prefixed with a $, so:
USERNAME=user
PASSWORD=sekrit
is the way to write what you wanted. You got an error because USERNAME was not set, so after expansion, the shell looked at the command as:
=user
=sekrit
and it could not find such commands on the system (not very surprisingly). However, be aware that if you have previously written:
USERNAME=archipelago
PASSWORD=anchovy
then the lines:
$USERNAME=user
$PASSWORD=sekrit
would have been equivalent to writing:
archipelago=user
anchovy=sekrit
You could see that by running set with no arguments; it would show you the values of all the variables set in the shell. You could search for words such as USERNAME and archipelago to see what happened.
Now you've learned that, forget it. The number of times you'll need to use it is very limited (but it is handy on those rare — very rare — occasions when you need it).
For all practical purposes, don't write a $ on the left-hand side of a variable assignment in shell.

Save Global variables BASH

I am new at bash and trying to solve some issues for a code I'm trying to make.
I am at the terminal under my user name and connect to bash
USER$
USER$ bash
bash$
now in the bash I am saving some variables f.e:
i=2
k=2
let p=$k*$i
now I want to use those variables outside the bash function
bash$exit
USER$
but now the variables are not there
I try using export, but it did not really work, could use ur help, tnx
Not possible. You cannot set environment variables in a parent process like this.
Unlike a DOS batch file, a Unix shell script cannot directly affect the environment of its calling shell.
You could consider using the . (dot) or source command to read and execute the script in the context of the calling shell. This means that changes made in the script do affect the environment (in general; you can still run into issues with sub-shells).
The other alternative is to have the script that sets the variables write the values in name=value format into a file which the calling script then reads (with . or source again).
The conventional solution is to add the settings to your .profile or . bashrc -- which you should use depends on your specific needs and your local Bash configuration; my first recommendation would be .profile, but then you have to avoid any bashisms because this file is shared with sh (so, no let, for example).
For more specific needs, put the commands in a file, and source it when you need it. You might also want to create a simple script to update the file with your current values.
# source this file to update $HOME/stuff
cat<<HERE>$HOME/stuff
i='$i'
k='$k'
p='$p'
export i k p
HERE
The syntax here is quite simple, but assumes you don't have values which can contain single quotes or otherwise free-form content. How to safely store arbitrary values which you don't have complete control over is a much more complex discussion; I am providing a simple solution for the basic use case where you merely need to save a few simple scalar values, like numbers.
To keep your variables when you connect to a remote system, look at the documentation for the tool you are using to connect. For example, ssh has configuration options for importing environment variables from the local system when starting a remote session.

Resources